我正在开发一个 Yesod 应用程序,并希望有textField一个修改后的fieldView. 首先,我尝试了这个:
textField
:: ( Monad m
, RenderMessage (HandlerSite m) FormMessage
)
=> Field m Text
textField = I.textField
{ fieldView = fieldView I.textField
}
据我所知,这textField应该与I.textField. 但是,我收到以下错误:
Foo.hs:37:19: error:
• Couldn't match type ‘HandlerSite m0’ with ‘HandlerSite m’
Expected type: FieldViewFunc m Text
Actual type: FieldViewFunc m0 Text
NB: ‘HandlerSite’ is a type function, and may not be injective
The type variable ‘m0’ is ambiguous
• In the ‘fieldView’ field of a record
In the expression: I.textField {fieldView = fieldView I.textField}
In an equation for ‘textField’:
textField = I.textField {fieldView = fieldView I.textField}
• Relevant bindings include
textField :: Field m Text
(bound at Foo.hs:36:1)
有趣的是,这种另一种写法很好用:
textField
:: ( Monad m
, RenderMessage (HandlerSite m) FormMessage
)
=> Field m Text
textField = f
{ fieldView = fieldView
}
where
f@Field {..} = I.textField
fieldView作为函数使用有问题吗?我现在很困惑。我尝试使用ScopedTypeVariablesto 链接m到m0,但它不起作用,我不明白为什么甚至需要它。什么阻止m匹配m0?
编辑:我刚试过:
textField
:: ( Monad m
, RenderMessage (HandlerSite m) FormMessage
)
=> Field m Text
textField = I.textField
{ fieldView = fieldView
}
where
Field {..} = I.textField
它失败了,所以我猜这个问题与提到I.textField两次有关。这很奇怪。它不像I.textField是一个类型类成员,它有多个定义可供选择,即使是这样,我也看不出是什么阻止了 ghc 推断它m并且m0是相同的......好吧HandlerSite是一个类型族,所以我从类型检查器的角度猜测,它可能导致不同的实例RenderMessage和不同的代码定义,这些代码以某种方式链接到I.textField. 我想我开始看到光明了。
编辑2:我想我可以像这样链接它们:
textField
:: ( Monad m
, RenderMessage (HandlerSite m) FormMessage
)
=> Field m Text
textField = (I.textField :: Field m Text)
{ fieldView = fieldView (I.textField :: Field m Text)
}
开启ScopedTypeVariables,但显然不是。
编辑3:按照逻辑,这有效:
textField
:: ( Monad m
, RenderMessage (HandlerSite m) FormMessage
)
=> Field m Text
textField = f
{ fieldView = fieldView f
}
where
f = I.textField
所以我想这与顶级绑定与本地绑定有关吗?