2013-05-07 51 views
0

完整的小白在這裏Haskell中,我試圖讓這個下面這段代碼的工作:哈斯克爾類型誤區分配變量

它的意圖是要接受列表的第一EXP元素,將它們連接起來,然後調用同樣的功能。

order (i) (l1)(l2) = 
     do exp <- (2^i) 
      l <- (take exp l1) ++ (take exp l2) ++ (order (i+1) (drop exp l1) (drop exp l2)); 
      return l 

我敢肯定,這遠不是慣用的哈斯克爾,但你必須從一些地方開始。

我得到的錯誤是在

exp <- (2^i) 

No instance for (Num [Int]) 
     arising from a use of `^' 
    Possible fix: add an instance declaration for (Num [Int]) 

這我真的不能確定這究竟意味着。是不是2和我的整數,然後應用指數函數將導致一個整數?

謝謝!

回答

5

我重寫了你的代碼,如下所示,並添加了一個main。

order _ [] [] = [] 
order i l1 l2 = 
       (take exp l1) ++ (take exp l2) 
     ++  (order (i+1) (drop exp l1) (drop exp l2)) 
     where 
     exp = 2^i 

main = print $ order 1 [1,2,3,4] [3,4,5,6] 

所做的第一個錯誤是,你的遞歸不會終止爲order總會再次調用本身。第二個錯誤是在使用do時,這引入了一個monad並且考慮到你是Haskell的新手,我會保持清醒一點。現在只用於I/O。

我希望這會有所幫助。

P.S:您收到的錯誤消息是說,Int的列表以數字方式使用,並且沒有默認實現。這可能是由於monad超出列表的do造成的,但是我將在Haskell中對其進行分解以給出準確的解釋。

3

do塊中的所有語句必須屬於相同的monad。這包括<-綁定的右側。因此,因爲第二條語句take exp l1 ++ ...的右側是一個列表,編譯器推斷2^i的類型也必須是一個列表。

這是因爲<-不僅僅是分配變量。在列表monad的情況下,它依次將左側的變量綁定到右側列表中的每個元素。

如果您只想在do塊中綁定變量而沒有任何其他效果,則應該使用let綁定而不是<-

do let exp = 2^i 
    l <- take exp l1 ++ ... 
    return l 

也就是說,這裏使用的do表示法是多餘的。單子法律,保障了do x <- m; return x是一樣的只是m,所以你可以直接把它寫成

order i l1 l2 = take exp l1 ++ ... 
    where exp = 2^i 
2

除了布萊恩的點,我想我可以幫助解釋你得到的特定錯誤的原因。

很大的原因是exp <- 2^ido塊不意味着「讓exp是的2^i值名稱」(你會表達一個do塊爲let exp = 2^i這個意思,但do塊ISN」反正你真正想要的是這裏)。

什麼exp <- 2^i的含義是「讓exp成爲由一元值2^i產生的值的名稱」。嘗試閱讀<-作爲「來自」而不是「是」。究竟「來自」意味着取決於所涉及的monad。所以對於這條線意味着什麼,2^i必須是某種monad中的值。具體來說,它的類型就像Monad m => m a,對於未知的ma

由於^運算符使用數字值,因此它會返回Num a => a類型的內容。因此,我們可以弄清楚2^i應該是(Monad m, Num (m a)) => m a類型,對於未知的ma

exp是從這個謎團中提取的m a,所以它的類型是a。下一行包括像take exp l1這樣的表達式。 take要求其第一個參數爲Int,因此exp必須是Int,因此我們可以看出,我們正在使用的未知a必須是Int。所以現在已知2^i的類型爲(Monad m, Num (m Int)) => m Int;它是某種單子整數。

在這一行你也有l <- (take exp l1) ++ ...。所以l也「來自」某種monadic價值。可以看到右側是某種列表(由於使用了++,takedrop)。參與do塊的monad必須始終相同,並且列表類型構造函數確實是monad。所以如果(take exp l1) ++ ...是一個東西的列表,那麼2^i也必須是一個東西的列表。

所以現在我們有2^i存在[Int]類型的(我們原先知道這是m a;該m是列表類型構造[]aInt)。但是我們也知道(使用^運算符)它必須是Num類型類的成員。 [Int]沒有Num的實例,這正是你得到的錯誤。

這只是可以從您編寫的代碼中派生出的許多不一致之一;這只是GHC在試圖分析時碰巧遇到的第一個。