<div><div>Hi.</div><div><br></div><div>Some time ago I forgot to forward this message to thie<a href="http://www.haskell.org/pipermail/haskell-cafe/2011-January/088060.html"> ur versus Haskell </a>discussion, (as usual)</div>

<div>---</div><div>The most impressive feature (of ur) is the compile time checking of conformance between the  form and  the form results. This can be done in Haskell using HList magic and </div><div>some class instances, I guess.</div>

<div>----</div><div>Since then I have been playing mentally with this. Recently I found  something </div><div>simple an interesting enough to share. (Although crude).</div><div><br></div><div> It is a kind of typed form fields</div>

<div><br></div><div>data Input a=   Input String Type a (String -&gt; Either String a)</div><div><br></div><div> </div><div>and a kind of heterogeneous list  to aggregate form fields and results with the operator (:*):</div>

<div>    Input a :*  Input b ;* Input c....</div><div>     a :* b :* c</div><div><br></div><div>and a (simulated for the purpose of demonstration)  send-receive function  that type match the form fields and the results:</div>

<div><br></div><div><br></div><div>*Main&gt; let form = Input &quot;&quot; Text &quot;stringdata&quot; novalidate :* Input &quot;&quot; Text (1::Integer) novalidate</div><div><br></div><div>*Main&gt; ask form  &gt;&gt;= \(a :* b) -&gt; return $ a ++ b</div>

<div><br></div><div>&lt;interactive&gt;:1:0:</div><div>    No instance for (FormDigest</div><div>                       (Input [Char] :* Input Integer) ([a] :* [a]))</div><div>      ......</div><div><br></div><div>notifying that there is no translation defined , because the result requires</div>

<div>two lists of the same type when the form gives a string and an Integer</div><div><br></div><div>But forcing the correct monomorphic types it does pattern match and return the values.</div><div><br></div><div><br></div>

<div>*Main&gt; ask form  &gt;&gt;= \ (a :* b) -&gt; print (&#39;s&#39;:a) &gt;&gt; print ( fromInteger $ b)</div><div>&quot;sstringdata&quot;</div><div>1</div><div><br></div><div><br></div><div>ask is just a simulation of HTTP one time interaction. It returns the input values.</div>

<div>The whole loop involves the rendering of the form, with render:</div><div><br></div><div>*Main&gt; render form</div><div>&lt;input type=&quot;Text&quot; name=&quot;var1&quot; value=&quot;stringdata&quot;/&gt;</div><div>

&lt;input type=&quot;Text&quot; name=&quot;var2&quot; value=1/&gt;</div><div><br></div><div>In a real case the results are read and validated from the the  post values.They</div><div>are  (or can be) ordered sequentially acording with Input field names.</div>

<div>The FormDigest instances do this work. There is no need to define new</div><div>FormDigest instances. (although non one to one field-result can be created)</div><div><br></div><div>The text is in literate haskell. There is a more elaborate example at the end.</div>

<div>I know that the instances are non tail recursive and there are factorization pending</div><div> but this is just a proof of concept:</div><div><br></div><div>&gt;  {-# LANGUAGE</div><div>&gt;      FlexibleInstances,</div>

<div>&gt;      MultiParamTypeClasses,</div><div>&gt;      TypeOperators</div><div>&gt;  #-}</div><div><br></div><div>&gt; import Control.Monad.State</div><div><br></div><div>The Heterogeneous list agregator. I tried to use GADTs but they does not </div>

<div>easily pattern match</div><div><br></div><div>&gt; data x :* xs =   x :* xs deriving (Read, Show, Eq)</div><div>&gt; infixr 5 :*</div><div><br></div><div><br></div><div>&gt; data Type= Hidden | Text deriving (Show, Read)    -- to add all the types</div>

<div><br></div><div>the input field, with text formatting, initial value and runtime validator</div><div><br></div><div>&gt; data Input  a =   Input String Type  a (String -&gt; Either [String] a)</div><div><br></div><div>

&gt; instance(Show a)=&gt; Show (Input a) where</div><div>&gt;   show (Input _ _ x _) = show x</div><div><br></div><div>rendering of the form need a sequentiation of field names. I use a state monad for this</div><div><br>

</div><div>&gt; class RenderForm a  where</div><div>&gt;  renderForm ::  a -&gt; State Int String</div><div><br></div><div>&gt; instance  (Show a) =&gt; RenderForm  (Input a) where</div><div>&gt;  renderForm  input = do</div>

<div>&gt;     s1 &lt;- render1 input</div><div>&gt;     n &lt;- get</div><div>&gt;     put $ n + 1</div><div>&gt;     return  s1</div><div><br></div><div>HList school here:</div><div><br></div><div>&gt; instance (Show a,RenderForm xs) =&gt; RenderForm (Input a :* xs) where</div>

<div>&gt;  renderForm  (input :* xs)= do</div><div>&gt;    n &lt;- get</div><div>&gt;    put $ n+1</div><div>&gt;    h &lt;- render1 input</div><div>&gt;    s &lt;- renderForm  xs</div><div>&gt;    return $ h++s</div><div>

<br></div><div>&gt; render1 (Input msg t x _)= do</div><div>&gt;    n &lt;- get</div><div>&gt;    put $ n+1</div><div>&gt;    return $ msg</div><div>&gt;            ++ &quot;&lt;input type=\&quot;&quot;</div><div>&gt;            ++ show t ++ &quot;\&quot; name=&quot;</div>

<div>&gt;            ++ &quot;\&quot;var&quot;++show n ++ &quot;\&quot; value=&quot;</div><div>&gt;            ++ show x ++&quot;/&gt;\n&quot;</div><div>&gt;</div><div><br></div><div>&gt; render form=    putStrLn $ evalState (renderForm   form ) 0</div>

<div><br></div><div>processing of the returned form result, in an ordered String list, according with</div><div>seuquential names of the fields defined in renderForm.</div><div><br></div><div>&gt; class  FormDigest a  b where</div>

<div>&gt;  formDigest :: a -&gt;  [String] -&gt; Either [String]  b</div><div><br></div><div>&quot;Input a&quot; is diggested into a type &quot;a&quot;</div><div><br></div><div>&gt; instance FormDigest (Input a) (a) where</div>

<div>&gt;   formDigest (Input _ _ x f) (s: ss)= case f s of</div><div>&gt;       Right x -&gt; Right $ x</div><div>&gt;       Left x  -&gt; Left x</div><div><br></div><div>recursively add instances for any  list  of inputs</div>

<div>Input a&#39;s are diggested into a&#39;s</div><div><br></div><div>&gt; instance  FormDigest as bs</div><div>&gt;           =&gt; FormDigest (Input a :* as) (a :* bs) where</div><div>&gt;  formDigest (input :* fs) es@(s:ss) =</div>

<div>&gt;       let er = formDigest fs ss</div><div>&gt;           e  = formDigest input es</div><div>&gt;       in case (e, er) of</div><div>&gt;           (Right x, Right  ys) -&gt;  Right $ x :* ys</div><div>&gt;           (Right _, Left errs) -&gt; Left errs</div>

<div>&gt;           (Left err, Left errs) -&gt;  Left (err ++ errs)</div><div><br></div><div><br></div><div><br></div><div>simulated request-response that returns the entered input values</div><div><br></div><div>&gt; sendRec xs= do</div>

<div>&gt;   let strs =   showValues xs</div><div>&gt;   return $ formDigest xs  strs</div><div><br></div><div>&gt; class ShowValues a where</div><div>&gt;    showValues :: a -&gt; [String]</div><div><br></div><div>&gt; instance Show x =&gt; ShowValues (Input x) where</div>

<div>&gt;     showValues i = [show i ]</div><div><br></div><div>&gt; instance (Show x,ShowValues xs) =&gt; ShowValues (Input x :* xs) where</div><div>&gt;     showValues (i :* xs)= show i : showValues xs</div><div><br></div>

<div>end of simulated request response</div><div><br></div><div>&gt; ask :: (ShowValues a,  FormDigest a b) =&gt; a -&gt; IO b</div><div>&gt; ask form = do</div><div>&gt;   er &lt;- sendRec form</div><div>&gt;   case er of</div>

<div>&gt;     Left errs  -&gt; error &quot;&quot; --  shoud be: &quot;ask1 errs  form &quot;·to render form and errors</div><div>&gt;     Right res -&gt; return res</div><div><br></div><div><br></div><div>EXAMPLE:</div><div>

<br></div><div>&gt; data Emp= Emp{name::String, salary :: Int} deriving Show</div><div><br></div><div>&gt; emp= Emp &quot;Luis&quot; 10000</div><div><br></div><div>toy html operators:</div><div><br></div><div>&gt; b  msg  =   (&quot;&lt;b&gt; &quot; ++ msg ++ &quot; &lt;/b&gt;\n&quot;)</div>

<div>&gt; p  msg  =   (&quot;&lt;p&gt; &quot; ++ msg ++ &quot; &lt;/p&gt;\n&quot;)</div><div><br></div><div>&gt; novalidate n=  Right $ read n</div><div><br></div><div>&gt; main= do</div><div><br></div><div>&gt;</div><div>

&gt;   let form  =   Input</div><div>&gt;                  (   b  &quot;please enter the name&quot;</div><div>&gt;                  ++  p &quot;mas texto&quot;)</div><div>&gt;                    Text (name emp) novalidate</div>

<div>&gt;                 :* Input</div><div>&gt;                  (b  &quot;please enter the salary&quot;</div><div>&gt;                  ++  p  &quot;jkjkjk&quot;)</div><div>&gt;                    Text (salary emp) novalidate</div>

<div><br></div><div>&gt;   render form </div><div><br></div><div>the matching thing</div><div><br></div><div>&gt;   (n :* s ) &lt;- ask   form</div><div><br></div><div>&gt;   print emp</div><div>&gt;   print $ Emp n s</div>

<div><br></div><br><br></div>