我正在尝试为 Yesod 构建 bootstrap 3 兼容性。但是,通过创建“renderBootstrap3”函数来做到这一点是不可能的,因为您无法将类添加到输入中。因此,我选择在 Form.Fields
中制作字段的 Bootstrap 版本。 .这个想法是我可以克隆普通字段,但在属性数组中添加一个类声明。以下是相关代码:
import qualified Yesod.Form.Fields as F
injectClass :: (Text -> Text -> [(Text,Text)] -> Either Text a -> Bool -> WidgetT (HandlerSite m) IO ()
Text -> Text -> [(Text,Text)] -> Either Text a -> Bool -> WidgetT (HandlerSite m) IO ()
injectClass f a b attrs d e = f a b attrs d e
textField :: (Monad m, RenderMessage (HandlerSite m) FormMessage) => Field m Text
textField = addInputClass F.textField
addInputClass :: (Monad m, RenderMessage (HandlerSite m) FormMessage) => Field m a -> Field m a
addInputClass f = f { fieldView = (injectClass $ fieldView f)}
因此,我的意图是采用普通版本的文本字段并使用记录语法仅修改 fieldView 方法。此方法应替换为除添加类属性外相同的方法。这还没有在上面的代码中实现。它可能看起来像:
injectClass f a b attrs d e = f a b (("class", "form-control") : attrs) d e
无论如何,问题是原始代码无法编译。我得到一个等式约束错误:
Could not deduce (HandlerSite m0 ~ HandlerSite m)
from the context (Monad m,
RenderMessage (HandlerSite m) FormMessage)
bound by the type signature for
addInputClass :: (Monad m,
RenderMessage (HandlerSite m) FormMessage) =>
Field m a -> Field m a
at Field/Bootstrap.hs:27:18-95
NB: `HandlerSite' is a type function, and may not be injective
The type variable `m0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Expected type: FieldViewFunc m a
Actual type: Text
-> Text
-> [(Text, Text)]
-> Either Text a
-> Bool
-> WidgetT (HandlerSite m0) IO ()
In the `fieldView' field of a record
In the expression: f {fieldView = (injectClass $ fieldView f)}
In an equation for `addInputClass':
addInputClass f = f {fieldView = (injectClass $ fieldView f)}
请注意
FieldViewFunc m a
定义为type FieldViewFunc m a
= Text -- ^ ID
-> Text -- ^ Name
-> [(Text, Text)] -- ^ Attributes
-> Either Text a -- ^ Either (invalid text) or (legitimate result)
-> Bool -- ^ Required?
-> WidgetT (HandlerSite m) IO ()
所以,我离得不远了。问题是(我认为)它没有认识到
injectClass
不会改变单子(monad)。但是,这对编译器来说应该是显而易见的。 injectClass
的类型签名对此很清楚。我正在寻找我需要做些什么来满足 GHC。感谢您的帮助,如果我能更清楚,请告诉我。
最佳答案
啊,类型族和非内射性。
这是发生了什么:我们正在尝试进行类型检查
f { fieldView = (injectClass $ fieldView f)}
问题不在于
injectClass
可能会改变m
是。问题是它不知道 m
是。它的输入,fieldView f
和上下文,设置 fieldView
f
的字段,两者都只告诉它HandlerSite m
是的,简单的事实是你无法弄清楚 m
是从那里。就像你有以下情况:type family F a
type instance F Int = Bool
type instance F Char = Bool
现在尝试传递
F Int
在哪里 F Char
预计会成功,因为它们都只是 Bool
.因此,试图通过 HandlerSite m0
在哪里 HandlerSite m
预期可能会成功,即使 m
不是 m0
!因此,类型检查器不能确定 m0
应该与 m
相同,所以你得到一个模棱两可的类型错误。此外,您无法通过手动注释轻松解决歧义,因为您会遇到同样的问题:您将告诉类型检查器
HandlerSite m
应该是,它已经知道了。你能删除
HandlerSite m
来自 injectClass
的类型签名完全用普通类型变量 h
替换它, 说?那应该可以解决您的问题,但我不确定它是否会产生任何新问题。
关于twitter-bootstrap - Haskell 等式约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18605814/