将runFormPost小部件放入元组中

时间:2014-01-06 04:43:14

标签: haskell yesod

我想为runFormPost生成的小部件(Html表单)提供一些上下文。我想我可以简单地将结果粘贴到一个元组中,我的上下文和模式在我的哈姆雷特中匹配,但由于Handler Monads,它变得具有挑战性。

我有一个带有以下类型签名的Monadic表单:

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

我在forM中渲染一系列表单,并使用我的Hamlet文件中的小部件列表。一切正常。

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

现在,我想为每个小部件添加一些数据并将其作为元组返回。对于这个简单的例子,我们假设我想添加一个String。我尝试使用以下代码,当我尝试在我的Hamlet文件中使用它时它不会编译(如果我在我的Hamlet文件中没有使用widgets列表,则编译它)

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

在我的Hamlet文件中,我尝试过这样的事情(x是我的String上下文):

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

我收到以下错误:

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'

到目前为止,我已尝试在fmap内使用liftMforM or map但我仍然遇到类似的错误。我还尝试在我的模式匹配中抛出Handler,这给了我一个错误,说Handler不在范围内。

有关如何将一些额外的信息附加到窗口小部件并在我的哈姆雷特文件中重复使用的任何想法?

谢谢!

1 个答案:

答案 0 :(得分:2)

问题是runFormPost产生的结果包含在monad中,Handler在这种情况下。

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

因此,您应该使用最初定义的未打包版本小部件来添加其他信息。使用您的第一个版本的widgets :: ((FormResult MyData, Widget), Enctype),然后您可以添加行

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

在您的hamlet文件中,您应该嵌入widgetsWithInfo :: (String, ((FormResult MyData, Widget), Enctype)

对于您的其他问题:您对fmap的意图对我来说似乎是正确的,但是(如果它不仅仅是一个错字)您的表达式括号不正确。您希望将fmap应用于runFormPost $ myForm rid rec的结果,因此您必须将该子表达式括起来:

fmap (\x -> ("Test", x)) (rumformPost $ myForm rid rec)