为什么这不是正确的实施?
instance Monad Lock where
(Working False x) >>= _ = Working False x
(Working True x) >>= f = f x
GHC吐出的错误是关于刚性类型变量的错误:
• Couldn't match type ‘a’ with ‘b’
‘a’ is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b. Lock a -> (a -> Lock b) -> Lock b
at src/Computers.hs:32:22
‘b’ is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b. Lock a -> (a -> Lock b) -> Lock b
at src/Computers.hs:32:22
Expected type: Lock b
Actual type: Lock a
我可能误解了错误,但是由于我的理解有限,编译器实际上需要我吐出不同的参数化类型,而不是相同的类型。
我尝试添加一个不带类型参数的不同构造函数(并且仅为测试更改语义) - 然后它工作正常:
instance Monad Lock where
Broken >>= _ = Broken
(Working False x) >>= _ = Broken
(Working True x) >>= f = f x
编辑: 实际上,Lock的定义是:
data Lock a = Working Bool a
答案 0 :(得分:5)
我假设您对Lock
的定义如下:
data Lock a = Working Bool a
现在,让我们看一下(>>=)
的类型:
(>>=) :: Lock a -> (a -> Lock b) -> Lock b
重要的是,(>>=)
(而不是实现者)的调用者可以选择a
和b
的值;例如,我可能会使用它,就好像它有类型:
(>>=) :: Lock Int -> (Int -> Lock Bool) -> Lock Bool
现在很明显为什么你的实现是不正确的:在
中Working False int >>= _ = Working False int
您将返回Lock Int
而不是Lock Bool
。
答案 1 :(得分:2)
来电者有一个Lock a
和一个a -> Lock b
函数,您>>=
的实施必须将这些内容合并为一个Lock b
。您没有提供Lock
的定义,但我认为它看起来像这样:
data Lock a = Working Bool a
您的实施中的问题是您有a
,Working
构造函数中的第二个字段,并且您需要b
才能生成Lock b
。您不能只返回Working False a
,因为这是Lock a
,而不是>>=
承诺返回的内容。从b
获取a
的唯一方法是通过用户的f
功能,所以你别无选择,只能调用它。
添加Broken
构造函数后,这种情况并非如此,您现在可以轻松地为任何Lock b
构建b
,因为Broken
没有&# 39; t需要参数化的任何类型的值。
您可以通过
的实现看到相同的基本现象(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
当您编写Nothing >>= f
时,没有a
来调用该函数,那么如何构建Maybe b
?同样,Nothing
就足够了,因为它并不关心参数化的类型。