Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applicative functors and records in purescript

In Haskell, I'm used to doing stuff like this.

data Foo = Foo { foo :: String, bar :: String }

mFoo :: (Monad m) => m String -> m String -> m Foo
mFoo foo bar = Foo <$> foo <*> bar

The same does not work in purescript, however. Is there a way to achieve the same outcome, ie keep the record syntax while allowing partial application via applicative functors when building the instance?

Thanks!

like image 407
Mike Avatar asked Oct 20 '25 10:10

Mike


1 Answers

In PureScript you don't have to define such a record type upfront. Polymorphic version:

mXY :: forall a b m. Apply m => m a -> m b -> m { x :: a, y :: b }
mXY foo bar = { x: _, y: _ } <$> foo <*> bar

-- | which can be rewritten using lift2:
mXY' = Control.Apply.lift2 { x: _, y: _ }

And a monomoprhic equivalent:

type Foo = { x :: String, y :: String }

mFoo :: forall m. Apply m => m String -> m String -> m Foo
mFoo = Control.Apply.lift2 {x: _, y: _ }

A "live demo" using wonderful try.purescript.org + custom gist:

https://try.purescript.org/?gist=a37f5f0c50e0640e34ea5a4788c0c999

Of course there is a practical value in using a newtype around Record too like:

newtype Foo' = Foo' { x :: String, y :: String }

and in such a case I would propose something like:

mFoo'' foo bar = map Foo' $ { x: _ , y: _ } <$> foo <*> bar

but I think that this could be expressed in a more elegant and shorter way which I don't know :-)

EDIT:

This is probably even nicer syntax using ado:

ado
  x <- foo
  y <- bar
  in Foo { x, y }
like image 139
paluh Avatar answered Oct 22 '25 05:10

paluh



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!