2012-08-15 68 views
3

我剛起步的單子,我想不通爲什麼這兩個表達式的計算結果是不同的:列表單子:>> =`和`return`行爲之間的區別`

ghci> [1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch) 
[(1,'a'),(1,'b'),(2,'a'),(2,'b')] 


ghci> return ([1,2],['a','b']) 
([1,2],"ab") 
+3

如果你解釋爲什麼你覺得他們應該是相同的您就有可能獲得一些見解。 – Squidly 2012-08-15 15:36:43

回答

10

類型是不同的,所以它的合理的行爲是不同的

第一表達式將類型檢查作爲Num t => [(t, Char)]

使用的[]如在單子的(>> =)表示,則推斷該單子應List monad和的上下文中http://en.wikibooks.org/wiki/Haskell/Understanding_monads/List(>> =)是concatMap,返回值是(:[])。

[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch) 

相同

concatMap (\n -> concatMap (\ch -> [(n, ch)]) ['a', 'b']) [1,2] 

返回[(1,'a'),(1,'b'),(2,'a'),(2,'b')]

在你的第二個例子中究竟發生了什麼事情是

,表達的類型是更普遍一點:

Prelude> :t return ([1,2],['a','b']) 
return ([1,2],['a','b']) :: (Monad m, Num t) => m ([t], [Char]) 

因爲您正在GHCi中運行它,所以會發生一些事情。 GHCi可以被認爲是一個非常大的特殊IO Monad。因此,由於沒有指定monad,所以當GHC嘗試打印結果時,在這種情況下,需要m Monad爲IO

t默認爲Integer,因此得到的表達式的類型爲:: IO ([Integer], [Char])

碰巧,所使用的所有類型的具有Show實例,因此GHC可以打印執行IO動作,在這種情況下(由於動作被返回)是一樣的作爲輸入的結果。

6

在GHCi中,您可以使用:t以交互方式檢查表達式的類型。這樣做表明,你的表情有不同的類型:

ghci> :t [1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch) 
[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch) 
    :: (Num t) => [(t, Char)] 

ghci> :t return ([1,2],['a','b']) 
return ([1,2],['a','b']) :: (Num t, Monad m) => m ([t], [Char]) 

因此,他們有不同的價值觀。

也許你對裏面的單子存在感到困惑return的說法。然而,看它的類型:

ghci> :t return 
return :: Monad m => a -> m a 

return一無所知它的參數 - 它只是需要一個值,任何值,並將其放置在默認情況下,一元上下文。


要準確理解,當這些表達式求值發生了,你將需要:

  1. Hoogle,找到列出單子實例,
  2. 第二更具體的類型表達

Here's單子實例:

instance Monad [] where 
    m >>= k    = foldr ((++) . k) [] m 
    m >> k    = foldr ((++) . (\ _ -> k)) [] m 
    return x   = [x] 
    fail _    = [] 

(我們可以,因爲我們不使用它們忽視>>fail。)

讓我們擴展我們的表達:

[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch) 

所以設置m = [1, 2]k = \n -> ['a','b'] >>= \ch -> return (n,ch)我們得到:

foldr ((++) . (\n -> ['a','b'] >>= \ch -> return (n,ch))) [] [1,2] 

現在擺脫第二個>>=,m = ['a', 'b']k = \ch -> return (n, ch)

foldr ((++) . (\n -> rest)) [] [1,2] 
    where 
    rest = foldr ((++) . (\ch -> return (n,ch))) [] ['a', 'b'] 

return很容易擺脫的:

foldr ((++) . (\n -> rest)) [] [1,2] 
    where 
    rest = foldr ((++) . (\ch -> [(n,ch)]) [] ['a', 'b'] 

在另一方面,第二表達式的值:

return ([1,2],['a','b']) 

取決於這單子你」重新在。在列表單子,它只是變成了:

[([1,2], ['a','b'])] :: [] ([Int], String) 

而在單子也許,它是:

Just ([1,2], ['a', 'b']) :: Maybe ([Int], String) 
+0

這真的很有幫助;如果我可以標記第二個最喜歡的答案,我肯定會。 – planarian 2012-08-15 15:41:27

相關問題