digestive-functors icon indicating copy to clipboard operation
digestive-functors copied to clipboard

ADT Forms or how to bind 2 forms?

Open superduper opened this issue 10 years ago • 3 comments

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.

superduper avatar Sep 26 '15 12:09 superduper

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

mightybyte avatar Sep 26 '15 13:09 mightybyte

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 [email protected] 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.

superduper avatar Sep 26 '15 14:09 superduper

@superduper wondering if you found a solution to this?

saurabhnanda avatar Jan 03 '17 18:01 saurabhnanda