[Haskell-cafe] dynamic web form generation for algebraic data types

Olaf Klinke olf at aatal-apotheke.de
Fri Mar 3 16:40:36 UTC 2023


Georgi, 

your're absolutely right and I hope that I was clear enough when
stating that Grace *does* have dynamic forms, but with the limitations
stated in the project README. In fact I shall study how they are
realized under the hood. Noon is right in that one should be careful
not to rely on the hippest JavaScript framework which will become
obsolete soon. 
I've experiemented a little and conclude that monads provide a suitable
abstraction for dynamic forms, because >>= facilitates generation of
form parts conditional on results of other form evaluations. 
A proof-of-concept with InputT IO as the monad is published at
https://hub.darcs.net/olf/GenericForm/browse/GenericForm.hs
In its current state, it is capable of generating forms for types such
as Either String (Int,Bool). 

I also realized that while Yesod's MForm is a monad (transformer),
running a form produces a list of FieldView values, which the
programmer must assemble into the actual form html. While hiding some
fields conditionally may be feasible with yesod-form, I think forms for
recursive types are out of the question. As I understand it, the
monadic structure of MForm means that field values are *evaluated*
conditionally, but the fields must be present statically. Maybe Michael
Snoyman can weigh in on this. 

Olaf

On Fri, 2023-03-03 at 09:58 +0200, Georgi Lyubenov wrote:
> Hey
> 
> With the risk of being annoying, I want to point out that the Grace 
> browser does indeed somewhat support
> your original use case, because I feel like it might not be something 
> obvious (there also is not an example for it, I think).
> 
> With the term
> ```
> merge
>      { Number: \n -> "The number is " + Real/show n
>      , Check: \b -> if b then "checked" else "unchecked"
>      }
> ```
> which is equivalent to pattern matching on the input and picking a case, 
> we get html with two radio buttons:
> * Check - when this is selected, the output is based on whether a 
> checkbox is checked
> * Number - when this is selected, the output is based on the value in an 
> input text field.
> 
> Of course, this is still suboptimal - the input text field and checkbox 
> are shown at all times,
> but I feel like I would have misrepresented the language if I did not 
> point out it does support something like this.
> 
> Cheers,
> Georgi
> 
> On 3/2/23 17:01, Olaf Klinke wrote:
> > On Thu, 2023-03-02 at 15:51 +0200, Georgi Lyubenov wrote:
> > > Hey Olaf,
> > > 
> > > This is not an answer to your question, but I was reminded of Grace[0],
> > > which is a language
> > > with a "browser"[1] that allows you to type in terms and get back
> > > webpages based on those terms
> > > "automagically", which sounds like exactly what you need. I don't know
> > > how it's implemented, so I don't know if
> > > it is actually relevant to you, but it is worth noting that Grace itself
> > > is implemented in Haskell.
> > > 
> > > Cheers,
> > > Georgi
> > > 
> > > [0] https://github.com/Gabriella439/grace
> > > [1] https://trygrace.dev/
> > > 
> > > On 3/2/23 12:54, Olaf Klinke wrote:
> > > > Dear Cafe,
> > > > 
> > > > has anyone ever attempted (and maybe succeeded) in building dynamic
> > > > forms using one of the Haskell web frameworks (Yesod,Servant,...)?
> > > > By "dynamic" form I mean a form that changes the number of fields based
> > > > on selections the user makes in other fields of the form.
> > > > 
> > > > For example, say one has an algebraic data type
> > > > 
> > > >       data T = Number Int | Check Bool T
> > > > 
> > > > A form for such a type would initially consist of radio buttons or a
> > > > drop-down list with options "Number" and "Check" that lets the user
> > > > select the constructor. When "Number" is selected, an <input
> > > > type="number"> field is shown. When "Check" is selected, an <input
> > > > type="checkbox"> is displayed next to another form of this kind.
> > > > 
> > > > In the end, one would use the GHC.Generics machinery to generate forms
> > > > for a wide range of algebraic data types. I've seen this in the Clean
> > > > language's iTask library [1] and it's very convenient.
> > > > Of course this would involve a lot of JavaScript like
> > > > document.createElement() as well as book-keeping how to re-asseble the
> > > > fields into a T value upon submission. At least the latter is already
> > > > handled by libraries such as yesod-form.
> > > > 
> > > > Olaf
> > > > 
> > > > [1] https://cloogle.org/src/#itasks/iTasks/UI/Editor/Generic
> > > > [2] https://github.com/haskell-servant/servant-swagger/issues/80
> > > > 
> > > > 
> > Thanks for the pointer!
> > 
> > The Grace README says under Notable Omissions:
> > 
> > > Recursion or recursive data types
> > > 
> > > Grace only supports two built-in recursive types, which are List and
> > > JSON, but does not support user-defined recursion or anonymous
> > > recursion.
> > > 
> > > User-defined datatypes
> > > 
> > > All data types in Grace are anonymous (e.g. anonymous records and
> > > anonymous unions), and there is no concept of a data declaration
> > The tutorial shows how Grace function inputs are mapped to forms, where
> > functions with List input indeed have a form that is "dynamic" in the
> > sense I defined. Otherwise there is only one input field per function
> > argument. That means complex types are to be input in JSON syntax and
> > parsed.
> > Instead of a DSL, I'd prefer a shallow embedding into Haskell, so that
> > one can leverage all the available machinery.
> > Yet Grace already goes a long way towards what I am after.
> > 
> > Olaf
> > 
> > 
> > 
> >   
> > 
> > 
> > 




More information about the Haskell-Cafe mailing list