Avoiding ad-hoc with yesod-form

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Avoiding ad-hoc with yesod-form

Yotam Ohad
Hello cafe,

I have a custom data type:
data Foo = Foo | Bar | Baz
    deriving (Show, Bounded, Enum)
In my yesod app I need to have two forms, one that get two Foo and a second that recieve three Foo. From What I've seen online I need to create two new data types:
data Foo2 = { foo1 :: Foo, foo2 :: Foo }
data Foo3 = { foo1 :: Foo, foo2 :: Foo, foo3 :: Foo }

This is tedious and very much ad-hoc. In my actual app it goes up to Foo6 :( Is there a better way to do it?

This is how I defined the forms: 
foo2AForm :: AForm Handler Foo2
foo2AForm = Foo2
    <$> areq (selectFieldList foos) "foo1" Nothing
    <*> areq (selectFieldList foos) "foo2" Nothing
  where
    foos:: [(Text, Role)]
    foos= map (pack . show &&& id) [minBound..]

foo2Form :: Html -> MForm Handler (FormResult Foo2, Widget)
foo2Form = renderTable teamAForm

foo3AForm :: AForm Handler Foo3
foo3AForm = Foo3
    <$> areq (selectFieldList foos) "foo1" Nothing
    <*> areq (selectFieldList foos) "foo2" Nothing
    <*> areq (selectFieldList foos) "foo3" Nothing
  where
    foos:: [(Text, Role)]
    foos= map (pack . show &&& id) [minBound..]

foo3Form :: Html -> MForm Handler (FormResult Foo2, Widget)
foo3Form = renderTable teamAForm

Thanks


_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Avoiding ad-hoc with yesod-form

MarLinn
On 2017-07-24 12:54, Yotam Ohad wrote:
>
> […]
>
> Is there a better way to do it?

Yes. AForm is Applicative. So you should just be able to use other
applicative combinators.

For example (untested):

        fooAForm :: Int -> AForm Handler [Foo]
        fooAForm count = traverse makeFooField [1..count]
          where

            makeFooField :: Int -> AForm Handler Foo
            makeFooField n = areq (selectFieldList foos) (makeFooName n) Nothing
       

            foos :: [(Text, Role)]
            foos = first tshow . join (,) <$> [minBound..]

Note that traverse works on any Traversable (Duh.), and the usual maps
are all Traversable, so you can easily adapt this to return, say, a
(Map String Foo) or a (Map FooName Foo). And similar methods work for
monadic forms.

But: The way you asked the question smells like there might be something
bad in either the user interface or the structural design. Maybe you
want just one form with six fields plus CSS to conditionally hide some
of them? Maybe you want one form with n fields plus an additional field
to select the n? (Monadic fields should be able to do that.) Maybe
there's no real maximum limit so you need just one field generator but a
more complex front-end? I'm not saying you're doing it wrong, it's just
that my nose is itching.

Cheers.


> This is how I defined the forms:
> foo2AForm :: AForm Handler Foo2
>
> foo2AForm = Foo2
>      <$> areq (selectFieldList foos) "foo1" Nothing
>      <*> areq (selectFieldList foos) "foo2" Nothing
>    where
>      foos:: [(Text, Role)]
>      foos= map (pack . show &&& id) [minBound..]
>
> […]
>
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Avoiding ad-hoc with yesod-form

Yotam Ohad
Hi,
Thanks, I'm feeling kinda dumb because I forgot this is applicative, but yet feeling amazed on how great Haskell is to let you do stuff like that.
Your nose may not have betrayed you, I'm using these forms to show rows from a database with added buttons to manage it from the web. On the other hand, I might be really bad at explaining my questions 
:)

‫בתאריך יום ב׳, 24 ביולי 2017 ב-15:54 מאת ‪MarLinn‬‏ <‪[hidden email]‬‏>:‬
On 2017-07-24 12:54, Yotam Ohad wrote:
>
> […]
>
> Is there a better way to do it?

Yes. AForm is Applicative. So you should just be able to use other
applicative combinators.

For example (untested):

        fooAForm :: Int -> AForm Handler [Foo]
        fooAForm count = traverse makeFooField [1..count]
          where

            makeFooField :: Int -> AForm Handler Foo
            makeFooField n = areq (selectFieldList foos) (makeFooName n) Nothing


            foos :: [(Text, Role)]
            foos = first tshow . join (,) <$> [minBound..]

Note that traverse works on any Traversable (Duh.), and the usual maps
are all Traversable, so you can easily adapt this to return, say, a
(Map String Foo) or a (Map FooName Foo). And similar methods work for
monadic forms.

But: The way you asked the question smells like there might be something
bad in either the user interface or the structural design. Maybe you
want just one form with six fields plus CSS to conditionally hide some
of them? Maybe you want one form with n fields plus an additional field
to select the n? (Monadic fields should be able to do that.) Maybe
there's no real maximum limit so you need just one field generator but a
more complex front-end? I'm not saying you're doing it wrong, it's just
that my nose is itching.

Cheers.


> This is how I defined the forms:
> foo2AForm :: AForm Handler Foo2
>
> foo2AForm = Foo2
>      <$> areq (selectFieldList foos) "foo1" Nothing
>      <*> areq (selectFieldList foos) "foo2" Nothing
>    where
>      foos:: [(Text, Role)]
>      foos= map (pack . show &&& id) [minBound..]
>
> […]
>

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Loading...