purescript-record icon indicating copy to clipboard operation
purescript-record copied to clipboard

Create a partially applied record constructor

Open chrisdone opened this issue 7 years ago • 7 comments

Consider this:

F <$> x <*> y <*> z

This 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?

chrisdone avatar Sep 05 '18 10:09 chrisdone

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?

garyb avatar Nov 11 '18 11:11 garyb

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. :+1:

chrisdone avatar Nov 12 '18 09:11 chrisdone

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 }

MonoidMusician avatar Nov 13 '18 03:11 MonoidMusician

That's a very attractive way to express this problem!

chrisdone avatar Nov 13 '18 10:11 chrisdone

I think Adam Saleh is the author of this part: https://github.com/justinwoo/purescript-record-extra/blob/685ac456ee8157403b34833d3989754a2ae237ea/src/Record/Extra.purs#L182

justinwoo avatar Nov 13 '18 11:11 justinwoo

Labeling as 'documentation' as it seems like the problem was addressed but the solution could be highlighted still.

JordanMartinez avatar Dec 04 '21 04:12 JordanMartinez

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.

chrisdone avatar Dec 04 '21 09:12 chrisdone