Haskell 如何为自定义新类型派生PersistField?
这是一个特定于YesSOD的问题,但即使不知道YesSOD,你也可以帮助我,这与新类型有关 假设我的config/models中有以下简化模型Haskell 如何为自定义新类型派生PersistField?,haskell,yesod,Haskell,Yesod,这是一个特定于YesSOD的问题,但即使不知道YesSOD,你也可以帮助我,这与新类型有关 假设我的config/models中有以下简化模型 Value userId UserId weight Weight deriving (Show) 我将在我的webapp中同时使用千克和磅,但我决定DB应该以千克为单位存储东西。为了使类型系统避免混淆两者,我定义了以下内容: newtype Weight = Kilograms Int deriving (Re
Value
userId UserId
weight Weight
deriving (Show)
我将在我的webapp中同时使用千克和磅,但我决定DB应该以千克为单位存储东西。为了使类型系统避免混淆两者,我定义了以下内容:
newtype Weight = Kilograms Int
deriving (Read, Show, Eq, PersistField, PersistFieldSql)
这很好,但我如何从表单中使用它
logForm :: UserId -> Form Value
logForm uid = renderDivs $ Value <$>
pure uid <*>
areq intField "Weight" Nothing
我尝试推导积分
,但它抱怨我没有实际权重
。一次又一次,我最终得到了:
newtype Weight = Grams Int
deriving (Read, Show, Eq, Enum, Ord, Num, Integral, Real, PersistField, PersistFieldSql)
这是正确的方法吗?好像有很多重复。有什么更好的方法
一般来说,如果我在Haskell a
newtype N = T a
对于具体类型
a
,如何让N
重新派生a
实例中的所有内容,并让N
派生一些其他类型类(在我的示例中是PersistField
和PersistFieldSql
)。非常感谢。字段与字段不同。您希望通过导入Yesod.Forms来创建自定义字段。下面是一个MathJax类型的示例;)
newtype MathJax=MathJax{unMathJax::Markdown}
派生(Eq、Ord、Show、Read、PersistField、PersistFieldSql、IsString、Monoid)
unMM::MathJax->Text
unMM=取消标记。取消Mathjax
mathJaxField::(Monad m,RenderMessage(HandlerSite m)FormMessage)=>字段m MathJax
mathJaxField=字段
{fieldParse=parseHelper$Right.MathJax.Markdown.Text.filter(/='\r')
,fieldView=\theId name attrs val\u isReq->toWidget
[哈姆雷特|$newline从不
#{任一id unMM val}
|]
,fieldEnctype=UrlEncoded
}
嘿,谢谢你的帮助。但是,您确定这是正确的方法吗?在这种情况下,底层类型只是一个简单的Int,而不是Markdown(为此您必须编写自己的fieldParse/fieldView?),是的,您必须编写自己的字段。字段类型将解析器(fieldParse记录)和呈现器(fieldView记录)组合在一起。因此,您需要将URL编码的Int解析为Int,然后再解析为newtype。同样,您需要打开新类型。但这是一个“最小”的案例。这是不可推导的,大概是因为您可能希望使用不同的方式来呈现或解析您的类型。这很奇怪,我在问题中所写的内容确实有效–我通常可以使用intField
并将其保存到DB–然后当我从DB中取回它并show
it时,我确实看到这个字段用千克
包裹起来。另一方面,将新类型更改为kg Double
,然后适当地使用双字段
,我不断发现无法将类型“Double”与“ModelTypes.Weight”匹配。为什么它适用于Int
而不是Double
,这很奇怪。我最终编写了自定义字段,就像您在这里展示的那样,所以接受了。如果您想办法对具有基础Int的新类型使用普通Int字段,而不必创建自定义新字段并保持类型安全,请告诉我。
newtype N = T a
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
}