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

Haskell错误:无法';t匹配类型';a';与';b';,haskell,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 ::

我是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[elem1,elem2]等于List[elem1,elem1,elem2]。我知道这不是一个使用单子的好例子,但那是为了学习

我遇到了这样的错误:

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变量。这里有什么问题

我知道这不是一个使用单子的好例子,但那是为了学习

具体来说,
>>=
的实现不够通用。您所提供的类型为:

列表a->(a->列表a)->列表a

但哈斯克尔坚持

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

在我看来,似乎没有好的方法来实现你想要的单子


更深层次的原因是您希望修改“容器”的结构,而不是以特定于容器的方式对“元素”进行处理。

以下是
NestedList
的一个工作monad实例,供您参考。验证该实例是否满足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]

您的问题是使用
joinlist
a'
Elem b
,而
xs
[Elem a]
。monad绑定是
(>>=)::monad m=>ma->(a->mb)->mb
@josejuna'的类型是
NestedList a=List[Elem a]
并且正确,
xs
[Elem a]或[NestedList a]
。JoinList采用NestedList a和[NestedList a],因此不会引起问题。如何将
[Elem a]转换为[Elem b]
?@AidasSimkus
f
具有类型
(a->mb)
,这就是类型变量
b
的来源。@AidasSimkus
a'
属于类型
Elem b
,因为
f::a->NestedList b
对于任何
b
。即使只与
f::a->NestedList a
一起使用,
Monad
也应该适用于
a
b
不同的函数。如何从剩余的
嵌套列表a
中创建
嵌套列表b
,取决于您。也许,将
f
应用到
xs
的每个元素会起作用,但这取决于您所做操作的逻辑。而且,
joinlist
没有
Elem a
的模式,所以您很快就会有这种感觉。谢谢!这正是我想要实现的。