2014-05-02 78 views
4

我是一個新望哈斯克爾,並有這段代碼:哈斯克爾錯誤:無法匹配類型「A」與「B」

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 

我所試圖做的是要接受列表使用元素,複製列表的第一個元素並向此列表添加尾部。因此,列表[Elem 1,Elem 2]將等於列表[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的不同類型的變量。這裏有什麼問題?

+0

你的問題是使用'joinLists','a''是'ELEM B'但'xs'是'[Elem a]'。 monad綁定是'(>> =):: Monad m => ma - >(a - > mb) - > mb' – josejuan

+0

@josejuan a'類型爲'NestedList a = List [Elem a]'且正確, 'xs'是'[Elem a]或[NestedList a]'。 joinLists需要NestedList a和[NestedList a],所以它不應該導致問題。我怎樣才能把'[Elem a]變成[Elem b]'? –

+0

@AidasSimkus'f'的類型爲'(a - > m b)',這就是類型變量'b'的來源。 –

回答

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] 
+0

謝謝!這就是我想要完成的事情。 –

7

I know that's not a good example of using Monads, but that's for the sake of learning.

具體而言,您的>>=的實施不夠通用。什麼你給具有類型:

List a -> (a -> List a) -> List a

但哈斯克爾在

List a -> (a -> List b) -> List b

堅持對我來說,它看起來像有實現你的單子要什麼沒有什麼好辦法。

更深層的原因是您想要修改「容器」的結構,而不是以容器特定的方式對「元素」進行操作。