[web-devel] Form Composition

Tyson Whitehead twhitehead at gmail.com
Fri Jun 24 06:23:54 CEST 2011


On Wed, Jun 22, 2011 at 5:23 AM, Jasper Van der Jeugt <m at jaspervdj.be>wrote:

> No, inputList is more applicable for a dynamic list, whereas your list
> consists of a fixed set of elements. Your problem can be solved more
> easily by creating a simple combinator, as I've described on the
> stackoverflow thread.
>

Thanks everyone for the input on this.  What I've been thinking, and what I
believe I'm seeing in other peoples solutions, is that the fundamental issue
in building these types of forms is the interpretation of later parts of the
form depends on the interpretation of the earlier parts of the form (e.g., a
hidden field giving the length of the list).

Of course applicative doesn't let you do this as it only lets you form fixed
sequences.  The additional power required is precisely what what the monad
structure adds.  Specifically, I'm thinking the join operator should let you
specify this wonderfully.  Under Yesod's GForm this would be

join :: GForm s m xml (GForm s m xml a) -> GForm s m xml a

The idea would be that your outer GForm would read (using the list example)
the hidden length parameter and use that to construct and return the (now
fixed structure as you know its length) inner GForm using applicative
composition like (as in the SO thread).  Apply join and you get a GForm
returning a list.

I was wanting to work it out exactly, but that would be several more days as
I'm a bit short on time and still not that familiar with the libraries, so
I'll just throw a rough sketch of usage

data Person = Person { age :: Int, name :: String }

personForm :: Maybe Person -> Form s m Person
personForm mperson = fieldsToDivs $ Person
  <$> intField "Age" (fmap age mperson)
  <*> stringField "Name" (fmap name mperson)

peopleForm :: [Maybe Person] -> Form s m [Person]
peopleForm mpeople = join $ build
  <$> fieldsToDivs $ intField "Number" (Just $ length mpeople)
  where
    build n = traverse personForm $ take n $ mpeople ++ repeat Nothing

The join should be pretty trivial to implement as GForm is a monad
transformer stack.  The only extra bit would be to do the equivalent of
wrapping the in inner form in a deeperFormIdent before splicing it in (as I
believe is currently being done with with the digest functors list handling
design).

Cheers!  -Tyson
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/web-devel/attachments/20110624/2d0f8108/attachment.htm>


More information about the web-devel mailing list