Create a partially applied record constructor
chrisdone opened this issue · 7 comments
Consider this:
F <$> x <*> y <*> zThis has a problem traditionally that you need to make sure you get the x/y/z order correct. If you're making forms (web forms) with e.g. a formlet library, this becomes pretty hard to manage.
What if we could do this?
partially F <$> pure {x:a} <*> pure {y:b} <*> pure {z:a}
(or alternatively by using SProxy :: SProxy "a", etc.)
So that partially F would produce a function of one argument of one of the x, y or z fields (or more, I guess). When provided with one, it accepts another argument until all fields have been consumed.
I made special version of <*> that achieves something similar:
module Record.Apply where
import Control.Applicative
import Prim.Row (class Nub, class Union)
import Record (disjointUnion)
-- API
applyFields
:: forall f inner outer combined.
Union inner outer combined
=> Nub combined combined
=> Apply f
=> f { | inner }
-> f { | outer }
-> f { | combined }
applyFields getInner getOuter =
disjointUnion <$> getInner <*> getOuter
infixl 5 applyFields as <|*>
-- Demo
newtype Foo = Foo { x :: Int, y :: String, z :: Array Int }
demo :: forall f. Applicative f => f Foo
demo = Foo <$> pure {y: ""} <|*> pure {x: 2} <|*> pure {z: []}
Which works nicely, but I think re-using <*> would be cool too. Any ideas?
I realise this is pretty old now, but for this kind of thing I've tended to do things like:
F <$> ({ x: _, y: _, z: _ } <$> a <*> b <*> c)
I guess the goal here was to make the applied field order non-specific though?
I guess the goal here was to make the applied field order non-specific though?
Right; so then one doesn't have to worry about argument order. 👍
I wonder if this wouldn't be better served by the general purpose "record sequence" feature (that exists somewhere, I'm sure, I just don't remember where off the top of my head).
F <$> sequenceRecord { x: pure a, y: pure b, z: pure a }
That's a very attractive way to express this problem!
I think Adam Saleh is the author of this part: https://github.com/justinwoo/purescript-record-extra/blob/685ac456ee8157403b34833d3989754a2ae237ea/src/Record/Extra.purs#L182
Labeling as 'documentation' as it seems like the problem was addressed but the solution could be highlighted still.
It’s still an interesting area generally.
See also https://gist.github.com/chrisdone/8ea87b30d3897a031de3ceeec690815e
I have a language with row types and I want a way to combine applicative things. I’d love to get a solution that uses the native row types, without stating the same field names twice, and also permitting custom ordering (important for a form).
So far I’m not satisfied with any ideas I’ve had. I forgot about this thread.