2016-07-14 56 views
2

为什么这不是一个正确的实现?Monad绑定坚持不同的类型?

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 

编辑: 的确,锁定的定义是:

data Lock a = Working Bool a 
+1

包含'Lock'的定义。 –

回答

5

我假设你的Lock定义是这样的:

data Lock a = Working Bool a 

现在,让我们看看(>>=)类型:

(>>=) :: Lock a -> (a -> Lock b) -> Lock b 

这里最重要的是,它是(>>=)(而不是实施者)的那个就可以选择的ab值调用者;为什么你的实现是不正确

(>>=) :: Lock Int -> (Int -> Lock Bool) -> Lock Bool 

现在很明显:例如,我可能会使用它,如果它有输入

Working False int >>= _ = Working False int 

你会返回一个Lock Int,而不是Lock Bool的。

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,这不是>>=承诺返回。您必须从a中获得b的唯一方法是通过用户的功能f,因此您只能称之为无法选择。

的原因,一旦你添加Broken构造,这是不正确的,是你可以轻松地构建一个Lock b现在,对于任何b,因为Broken不需要它在参数化类型的任何值。

你可以看到相同的基本现象与

(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b 

实施当你写Nothing >>= f,没有a调用的函数,那么如何才能Maybe b构建?再次,Nothing就足够了,因为它不关心它用哪个类型进行参数化。