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

ADT Forms or how to bind 2 forms? #122

Open
superduper opened this issue Sep 26, 2015 · 3 comments
Open

ADT Forms or how to bind 2 forms? #122

superduper opened this issue Sep 26, 2015 · 3 comments

Comments

@superduper
Copy link
Contributor

Hi! I want to make a form for an ADT. But can't figure how do I do that.

Given we have a type:

data Policy = Simple Int | Multi Int Int

How do we implement?

policyForm :: Form Text m Policy

Form would look this way:

{
  "type": "PolSimple"
  "cfg": {
    "a": 1
  }
}
or 
{
  "type": "PolMulti"
  "cfg": {
    "a": 1,
    "b": 1
  }
}

One direction I was thinking of is:

-- Add helper type to select a form
data PolType = PolSimple | PolMulti deriving (Show, Read, Eq, Bounded)

polForm :: Form Text m PolType
polForm = "type" .: stringRead Nothing

policyForm' :: PolType -> Form Text m Policy
policyForm' PolSimple = Simple <$> "a" .: stringRead Nothing
policyForm' PolMulti  = Multi  <$> "a" .: stringRead Nothing
                               <*> "b" .: stringRead Nothing

And I'm stuck here. What should we use to combine policyForm' and polForm? This could be possible if Form would be an instance of Monad, but thats not our case.

policyForm = ??? 

There's another way: we could make a union type of Simple and Multi with each field wrapped in Maybe. Then transform it via validate to Simple or Multi. But it wouldn't work well if we have a bit more complexity in our ADT (like Multi [(Text, Int)]). Can we do better? :)

Regards,
Viktor.

@mightybyte
Copy link
Contributor

AFAIK there's no way to do this with digestive-functors because the applicative interface is not powerful enough to express it. You've been thinking about it from the Haskell side, but try thinking about it from the GUI side. What would a form like this look like? You would probably have a dropdown with each of the constructors of your sum type. Then the rest of the form would have to be dynamically chosen based on the value of that dropdown. This will require some javascript to do the dynamic changing of the DOM, but digestive-functors doesn't have the ability to generate javascript.

"But that's not true!" you say. "The listOf combinator uses javascript to facilitate dynamic lists." And that is true, but that uses custom coded javascript that took a lot of work to get right. Also, since lists are homogeneous, it doesn't have to handle the generic case where the structure of one part of the form is a function of a previous part of the form.

You really need full-blown FRP to express this kind of thing generally. I would recommend reflex (introductory video here).

@superduper
Copy link
Contributor Author

Thanks for sharing your thoughts.

I don't use form generation. I use digestive-functors-aeson in order to validate API input.

Seems I have to make a monad instance for Form v m a.

On 26 Sep 2015, at 15:35, Doug Beardsley notifications@github.com wrote:

AFAIK there's no way to do this with digestive-functors because the applicative interface is not powerful enough to express it. You've been thinking about it from the Haskell side, but try thinking about it from the GUI side. What would a form like this look like? You would probably have a dropdown with each of the constructors of your sum type. Then the rest of the form would have to be dynamically chosen based on the value of that dropdown. This will require some javascript to do the dynamic changing of the DOM. Digestive-functors doesn't have the ability to generate javascript.

"But that's not true!" you say. "The listOf combinator uses javascript to facilitate dynamic lists." And that is true, but that uses custom coded javascript that took a lot of work to get right. Also, since lists are homogeneous, it doesn't have to handle the generic case where the structure of one part of the form is a function of a previous part of the form.

You really need full-blown FRP to express this kind of thing generally. I would recommend reflex (introductory video here).


Reply to this email directly or view it on GitHub.

@saurabhnanda
Copy link

@superduper wondering if you found a solution to this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants