类型推断 - 无法推断Monad
问题描述:
我正在构建一种向用户显示对话框的方法。类型推断 - 无法推断Monad
data DialogConfig t m b e =
DialogConfig { _dialogConfig_title :: Dynamic t T.Text
, _dialogConfig_content :: b -> m (Dynamic t (Maybe b))
, _dialogConfig_footer :: Dynamic t (Maybe b) -> m (Event t e)
}
dialog :: MonadWidget t m =>
DialogConfig t m b e -> Event t b -> m (Event t (DialogEvent e))
我想用某种形式的“默认”实例的初始化DialogConfig
为dialog
功能,这样我就可以把它作为例如defaultConfig{_dialogConfig_content=content}
。但是,我正在与类型推理战斗。这工作:
confirmDialog :: forall t m. MonadWidget t m =>
T.Text -> Event t T.Text -> m (Event t())
...
evt <- dialog
(DialogConfig { _dialogConfig_title = constDyn title
, _dialogConfig_content = content
, _dialogConfig_footer = buttons}
) contentEvt
然而,当我使用了一些默认DialogConfig
(如直接在这里它内联),这不:
evt <- dialog
(DialogConfig { _dialogConfig_title = constDyn mempty
, _dialogConfig_content = const $ return $ constDyn Nothing
, _dialogConfig_footer = const $ return never }
{ _dialogConfig_title = constDyn title
, _dialogConfig_content = content
, _dialogConfig_footer = buttons}
) contentEvt
的错误是:
Could not deduce (Reflex t0) arising from a use of ‘constDyn’ from the context (MonadWidget t m)
Could not deduce (Monad t1) arising from a use of ‘return’ from the context (MonadWidget t m)
我可以使用ScopedTypeVariables
并键入confirmDialog
中的默认配置为DialogConfig t m a b
,那可行,但是即使没有它,它也不能工作吗?在我看来,类型是相当明确的。
答
正如在评论中提到的那样,问题是记录更新可以更改记录的类型(最初可能会令人惊讶)。下面是GHCI测试:
> data T a = T { tA :: a }
> let x = T "foo"
> :t x
x :: T [Char]
> :t x { tA = True }
x { tA = True } :: T Bool
所以,我们不能定义默认:
> let def :: Read a => T a ; def = T (read "True")
> :t def :: T Bool
def :: T Bool :: T Bool
> :t def { tA = 5 }
Could not deduce (Read t0) arising from a use of ‘def’
The type variable ‘t0’ is ambiguous
事实上,上述def
可以是任何类型的。
一个可能的解决方案可能是通过要求T a -> T a
连续函数强制更新具有相同的类型。
> let defF :: Read a => (T a -> T a) -> T a ; defF f = f (T (read "True"))
> :t defF (\d -> d { tA = False })
defF (\d -> d { tA = False }) :: T Bool
以上d
是,通过建设,必须有更新后的同类型记录的默认值。
有了镜头,可能会有更好的方法。
+0
我会接受这个答案 - 是的,更新可以改变类型的事实是意想不到的,虽然很合理。 – ondra
[reflex-dom-contrib]中有一个非常好的(尽管仍然是实验性的)模态对话框公式(https://github.com/reflex-frp/reflex-dom-contrib/blob/master/src/ Reflex/Dom/Contrib/Widgets/Modal.hs) – user2847643
我们决定暂时自行实施...... – ondra
这些错误可能是由于以前的记录更新中的值未使用,所以它们的类型将会自然会含糊不清。看起来,基本问题是记录更新可能会改变记录的类型。要获得所需的类型推断,您必须以不改变类型的方式定义更新记录的某种方式(例如镜头)。 – user2407038