4

我正在尝试运行它

newtype Test a = Test (Int, a)

instance Monad Test where
    Test (_, []) >>= k =
        k []
    Test (_, a) >>= k =
        k a
    return a =
        Test (0, a)

我得到了错误:

Couldn't match expected type `a' with actual type `[t0]'
  `a' is a rigid type variable bound by
      the type signature for >>= :: Test a -> (a -> Test b) -> Test b
      at C:\Users\david.phillips\Documents\code\test.hs:4:5
In the pattern: []
In the pattern: (_, [])
In the pattern: Test (_, [])

当我尝试使用 case 语句而不是 >>= 的 2 个版本时,我得到了类似的错误。

我对haskell还很陌生,不明白为什么这不起作用。


编辑:对不起,这是一个不好的例子。假设 >>= 的第一个定义给出了不同的输出。

4

3 回答 3

8
class Monad m where
  (>>=) :: m a -> (a -> m b) -> m b
  (>>) :: m a -> m b -> m b
  return :: a -> m a
  fail :: String -> m a

Monad实例通过类型变量参数化a。您实际上是在声称它不是,因为在该变量的位置,您在空列表构造函数上匹配了模式[],这意味着“a 是某物的列表”。例如的类型。bind 可以通过明确的量化写成:

(>>=) :: forall a. m a -> (a -> m b) -> m b

您的定义不可能适用于 ALL a

于 2013-10-24T14:12:09.867 回答
3

作为莎拉答案的补充,您实际上可以省略您的特定模式匹配,

 Test (_, []) >>= f = f []

是相同的

 Test (_, a) >>= f = f a

所以你真的可以把它写成

 Test (_, a) >>= f = f a
 return a          = (0, a)

现在请记住,除了拥有正确的类型之外,我们还应该拥有

 m >>= return    = m
 return a >>= f  = f a
 (a >>= b) >>= c = a >>= (\a' -> b a' >>= c)

这让我很担心,因为

 m = Test (1, 'c')
 m >>= return === return 'c' === (0, 'c') /== m

所以return不再作为一个身份发挥作用,你正在违反第一条单子定律。解决这个问题意味着return必须保留元组的第一个元素,这是有问题的,因为我们实际上并没有告诉它。

天真地,让我们破坏函数返回的第一个元组元素。

 Test (a, b) >>= f = Test (a, snd (f b))

现在

 Test (1, 'c') >>= return == Test (1, snd (return 'c')) == Test (1, 'c')

但我们仍然有麻烦,

 let f a = Test (1, a)
 return a >>= f == Test (0, snd (f a)) == Test (0, a) /== f a

所以这里的诀窍是做 state monad 所做的事情

 newtype Test a = Test{ unTest :: Int -> (Int, a) }

 instance Monad Test where
   return a = Test $ \i -> (i, a)
   (Test m) >>= f = Test $ \i -> let (i', a) = m i
                    in unTest (f a) $ i'

这确实满足单子定律*。令人高兴的是,这已经存在于Control.Monad.State.

** 模数seq

于 2013-10-24T14:16:41.807 回答
0

摆脱第一个模式。您正在尝试为特定类型单独定义,这是您无法做到的。所有定义都需要适用于所有类型a。如果你可以违反这一点,第一个模式将与第二个模式相同,但a绑定到[],所以只需编写:

instance Monad Test where
    Test (_, a) >>= k =
        k a
    return a =
        Test (0, a)

Test (0, []) >>= k然后将匹配该>>=模式,并变得k []与您的第一个模式不必要地尝试做的完全一样。

于 2013-10-24T14:16:32.263 回答