Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a partially applied record constructor #49

Open
chrisdone opened this issue Sep 5, 2018 · 7 comments
Open

Create a partially applied record constructor #49

chrisdone opened this issue Sep 5, 2018 · 7 comments
Labels
type: documentation Improvements or additions to documentation.

Comments

@chrisdone
Copy link

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?

@garyb
Copy link
Member

garyb commented Nov 11, 2018

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 garyb added the idea label Nov 11, 2018
@chrisdone
Copy link
Author

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. 👍

@MonoidMusician
Copy link

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 }

@chrisdone
Copy link
Author

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

@justinwoo
Copy link
Contributor

@JordanMartinez JordanMartinez added the type: documentation Improvements or additions to documentation. label Dec 4, 2021
@JordanMartinez
Copy link
Contributor

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

@chrisdone
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: documentation Improvements or additions to documentation.
Projects
None yet
Development

No branches or pull requests

5 participants