1

这是我的问题的后续行动:Extracting database field values inside a Handler

我想从数据库中提取一些信息并将其作为表单的标签值传递。但是,我收到类型错误。

下面是一个简单的演示(来自 Yesod Book 的 shell 代码):

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeFamilies          #-}
import           Control.Applicative ((<$>), (<*>))
import           Data.Text           (Text)
import           Data.Time           (Day)
import           Yesod
import           Yesod.Form.Jquery

data App = App

mkYesod "App" [parseRoutes|
/ HomeR GET
|]

instance Yesod App

instance RenderMessage App FormMessage where
    renderMessage _ _ = defaultFormMessage

instance YesodJquery App

data Person = Person
    { personName          :: Text
    }
  deriving Show

personForm :: Text -> Html -> MForm Handler (FormResult Person, Widget)
personForm n1 = renderDivs $ Person
    <$> areq textField n1 Nothing  -- Changing n1 to "Name" works just fine. 


getHomeR :: Handler Html
getHomeR = do
    (widget, enctype) <- generateFormPost $ personForm "test"
    defaultLayout
        [whamlet|
            <p>
                The widget generated contains only the contents
                of the form, not the form tag itself. So...
        |]


main :: IO ()
main = warp 3000 App

当我使用 runhaskell 运行程序时,出现以下错误:

Couldn't match expected type `FieldSettings site0'
            with actual type `Text'
In the second argument of `areq', namely `n1'
In the second argument of `(<$>)', namely
  `areq textField n1 Nothing'
In the second argument of `($)', namely
  `Person <$> areq textField n1 Nothing'

我也试过 (FieldSettings n1 Nothing Nothing Nothing []) 但没有运气。关于如何将标签值传递给 areq 的任何想法?

4

1 回答 1

1

Let us look at the type of areq

areq :: (RenderMessage master msg, RenderMessage master FormMessage) => Field sub master a -> FieldSettings msg -> Maybe a -> AForm sub master a

So the areq function doesn't expect a Text value as its second parameter, it expects a FieldSettings msg. So what is the reason that it works when you write "Name" in your source code?

Looking up the documentation for FieldSettings in the documentation for yesod-forms we see that it is a datatype that has an IsString instance. Looking at the specific instance in the source code we see that:

instance (a ~ Text) => IsString (FieldSettings a) where
fromString s = FieldSettings (fromString s) Nothing Nothing Nothing []

So everytime you write a String in your source code (if the OverloadedStrings extension is enabled), the compiler will insert the contents of the fromString instance.

However, you don't want to enter a String, but instead you want to create a FieldSettings from a Text value. Looking further we see that the first part of a FieldSettings is a SomeMessage, checking the documentation yet again and the source we see that a SomeMessage can be created by using the SomeMessage constructor.

personForm :: Text -> Html -> MForm Handler (FormResult Person, Widget)
personForm n1 = renderDivs $ Person
    <$> areq textField (FieldSettings (SomeMessage n1) Nothing Nothing Nothing []) Nothing
于 2013-07-27T22:15:57.163 回答