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!
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 }