Haskell错误:无法将类型'a'与'b'匹配

时间:2014-05-02 10:22:38

标签: haskell

我是Haskell的新手并拥有这段代码:

import Control.Monad

data NestedList a = Elem a | List [NestedList a] deriving (Show)

instance Monad NestedList where
    return a = List [Elem a]
    (List (Elem a: xs)) >>= f = let a' = f a in a' `joinLists` xs

func :: a -> NestedList a
func a = List ([Elem a] ++ [Elem a])

joinLists :: NestedList a -> [NestedList a] -> NestedList a
joinLists (List a) b = List (a ++ b)

main = do let a = List [Elem 1, Elem 2] >>= func
          print a

我要做的是使用带有元素的List,复制列表的第一个元素并在此列表中添加尾部。所以List [Elem 1,Elem 2]将等于List [Elem 1,Elem 1,Elem 2]。我知道这不是使用Monads的好例子,但这是为了学习。

我收到这样的错误:

Couldn't match type 'a' with 'b'
   'a' is a rigid type variable bound by
       the type signature for
          '>>= :: NestedList a -> (a -> NestedList b) -> NestedList b
   'b' is a rigid type variable bound by
       the type signature for
          '>>= :: NestedList a -> (a -> NestedList b) -> NestedList b
   Expected type: [NestedList b]
   Actual type: [NestedList a]
   In the second argument of 'joinLists', namely 'xs'

我理解错误是它需要NestedList的不同类型变量。这有什么问题?

2 个答案:

答案 0 :(得分:7)

  

我知道这不是使用Monads的好例子,但那是为了学习。

具体来说,>>=的实施不够通用。你给出的是:

  

列出a - > (a - >列出a) - >列出一个

但是Haskell坚持

  

列出a - > (a - >列表b) - >列表b

对我来说,看起来没有好办法在monad中实现你想要的东西。

更深层次的原因是你想要修改“容器”的结构,而不是以容器特定的方式对“元素”做某事。

答案 1 :(得分:2)

供您参考,这是NestedList的工作单子实例。验证此实例是否符合monad定律应该不是很困难。

import Control.Monad

data NestedList a = Elem a | List [NestedList a] deriving (Show)

instance Monad NestedList where
    return x = Elem x
    (Elem x)  >>= f = f x
    (List xs) >>= f = List $ map step xs
        where step (Elem a) = f a
              step lst = lst >>= f

这是一个测试程序:

import Control.Monad

data NestedList a = Elem a | List [NestedList a] deriving (Show)

instance Monad NestedList where
    return x = Elem x
    (Elem x)  >>= f = f x
    (List xs) >>= f = List $ map step xs
        where step (Elem a) = f a
              step lst = lst >>= f


double :: a -> NestedList a
double a = List ([Elem a] ++ [Elem a])


add :: (Num a) => a -> a -> NestedList a
add a e = Elem $ a + e


main = do let a = Elem 1 >>= double
          let b = List [Elem 1, Elem 2] >>= double
          let c = List [Elem 2,List [Elem 3,Elem 4],Elem 5] >>= add 1
          print a
          print b
          print c

及其输出:

$ runhaskell t.hs 
List [Elem 1,Elem 1]
List [List [Elem 1,Elem 1],List [Elem 2,Elem 2]]
List [Elem 3,List [Elem 4,Elem 5],Elem 6]