这是一个特定于Yesod的问题,但是即使不知道Yesod,您也可以帮助我,它与新类型有关。
说我的配置/模型中有以下简化模型
Value
userId UserId
weight Weight
deriving (Show)
我将在我的web应用程序中同时使用千克和磅,但是我决定数据库应该以千克存储东西。为了获得防止我混淆两者的类型系统,我定义以下内容:
newtype Weight = Kilograms Int
deriving (Read, Show, Eq, PersistField, PersistFieldSql)
编译很好,但是如何从表单中使用它呢?
logForm :: UserId -> Form Value
logForm uid = renderDivs $ Value <$>
pure uid <*>
areq intField "Weight" Nothing
我得到了错误
No instance for (Integral ModelTypes.Weight)
arising from a use of `intField'
我尝试派生
Integral
,但随后它抱怨我没有Real Weight
。不断地,我最终得到:newtype Weight = Grams Int
deriving (Read, Show, Eq, Enum, Ord, Num, Integral, Real, PersistField, PersistFieldSql)
这是正确的方法吗?似乎有很多重复。有什么更好的方法呢?
一般来说,如果我在Haskell有一个
newtype N = T a
对于具体的
a
类型,我如何才能让N
重新推导a
所包含的所有内容,还如何让N
派生其他一些类型类(在我的示例PersistField
和PersistFieldSql
中)。非常感谢。 最佳答案
PersistField与Field不同。您想通过导入Yesod.Forms创建一个自定义字段。这是MathJax类型的示例;)
newtype MathJax = MathJax { unMathJax :: Markdown }
deriving (Eq, Ord, Show, Read, PersistField, PersistFieldSql, IsString, Monoid)
unMM :: MathJax -> Text
unMM = unMarkdown . unMathJax
mathJaxField :: (Monad m, RenderMessage (HandlerSite m) FormMessage) => Field m MathJax
mathJaxField = Field
{ fieldParse = parseHelper $ Right . MathJax . Markdown . Text.filter (/= '\r')
, fieldView = \theId name attrs val _isReq -> toWidget
[hamlet|$newline never
<textarea id="#{theId}" name="#{name}" *{attrs}>#{either id unMM val}
|]
, fieldEnctype = UrlEncoded
}