Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Putting the runFormPost widget into a tuple

Tags:

haskell

yesod

I would like to provide some context for the widgets (Html Forms) that are being generated by runFormPost. I thought I can simply stick the result into a Tuple with my context and pattern match it in my Hamlet but it turning out to be challenging because of Handler Monads.

I have a Monadic form with the following type signature:

myForm :: ModelId -> Model -> Html -> MForm Handler (FormResult MyData, Widget)
myForm rid rec extra = do
     -- whamlet code here

I render a series of forms inside forM and use the list of widgets in my Hamlet file. It all works fine.

widgets <- forM rs' $ \(Entity rid rec) ->
          runFormPost $ myForm rid rec

Now, I would like to add some data to each widget and return it as a tuple. For this simple example, let's assume I want to add a String. I tried the following code and it does not compile when I try to use it in my Hamlet file (it compiles if I don't use widgets list in my Hamlet file)

widgets <- forM rs' $ \(Entity rid rec) ->
          return ("Test", runFormPost $ myForm rid rec)

In my Hamlet file, I tried something like this (x is my String context):

$forall (x,((res,widget), enctype)) <- widgets
     <div>
        <form method=post action=@{HandlerR hId} enctype=#{enctype}>
           ^{widget}

I get the following error:

Couldn't match expected type `((t0, a1), a0)'
            with actual type `Handler ((FormResult MyData, Widget), Enctype)'
Expected type: [(t1, ((t0, a1), a0))]
  Actual type: [(t1,
                 Handler ((FormResult MyData, Widget), Enctype))]
In the second argument of `Data.Foldable.mapM_', namely `widgets'

So far I have tried using fmap and liftM inside forM or map but I keep getting a similar error. I also tried throwing Handler in my pattern match which gave me an error saying Handler not in scope.

Any thoughts on how I can append some additional piece of info to a widget and re-use it in my Hamlet file?

Thanks!

like image 229
Ecognium Avatar asked Mar 19 '26 06:03

Ecognium


1 Answers

The problem is that runFormPost yields a result which is wrapped in a monad, Handler in this case.

widgets :: (String, Handler ((FormResult MyData, Widget), Enctype)

So, you should use the unwrapped version widgets which you defined at first, to add your additional information. Using your first version of widgets :: ((FormResult MyData, Widget), Enctype), you can then add the line

let widgetsWithInfo = map (\w -> ("test", w)) widgets

In your hamlet file, you should then embed widgetsWithInfo :: (String, ((FormResult MyData, Widget), Enctype).

To your additional question: Your intention with fmap seems right to me, but (if it's not just a typo) your expression is parenthesised incorrect. You want to apply fmap to the result of runFormPost $ myForm rid rec, so you have to parenthesise that subexpression:

fmap (\x -> ("Test", x)) (rumformPost $ myForm rid rec)
like image 187
ichistmeinname Avatar answered Mar 22 '26 05:03

ichistmeinname



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!