类型推断 - 无法推断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)) 

我想用某种形式的“默认”实例的初始化DialogConfigdialog功能,这样我就可以把它作为例如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,那可行,但是即使没有它,它也不能工作吗?在我看来,类型是相当明确的。

+1

[reflex-dom-contrib]中有一个非常好的(尽管仍然是实验性的)模态对话框公式(https://github.com/reflex-frp/reflex-dom-contrib/blob/master/src/ Reflex/Dom/Contrib/Widgets/Modal.hs) – user2847643

+0

我们决定暂时自行实施...... – ondra

+3

这些错误可能是由于以前的记录更新中的值未使用,所以它们的类型将会自然会含糊不清。看起来,基本问题是记录更新可能会改变记录的类型。要获得所需的类型推断,您必须以不改变类型的方式定义更新记录的某种方式(例如镜头)。 – user2407038

正如在评论中提到的那样,问题是记录更新可以更改记录的类型(最初可能会令人惊讶)。下面是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