2010-06-29 19 views
28

我在Real World Haskell的I/O章節。本書不討論Monad的另外7章。也就是說,我對I/O的理解充其量是不完整的。map對mapM行爲

現在我正試圖理解mapM函數。據我所知,函數「執行」列表中的每個元素必須是「動作」(IO monad)。

沒有任何意義的是this example。爲什麼mapM對於相同的參數返回與map不同的結果?

Prelude> map (\x -> [x]) [0, 1, 2] 
[[0],[1],[2]] 
Prelude> mapM (\x -> [x]) [0, 1, 2] 
[[0,1,2]]
+0

也有趣:'長度(mapM(\\ _-> a)b)==長度a ^長度b'。我認爲。 – muhmuhten 2010-06-29 01:08:45

回答

18

據我所知,函數「執行」,其中必須是一個「動作」列表中的每個元件(IO單子)。

這是真的爲IO,但在你的代碼示例,你不使用IO單子,您可以使用列表單子(你給MAPM函數返回一個列表([x]),而不是一個IO)。

mapM定義爲mapM f as = sequence (map f as)。如果f返回一個IO,這意味着對於列表中的每個元素,它通過將f應用到元素來構造一個IO。然後它將映射返回的IO列表轉換爲包含使用序列的列表的IO(因此,當您執行IO時,將返回包含非IO值的列表)。

對於列表,它意味着它通過將f應用於as的每個元素來創建列表的列表。然後它使用sequence來創建一個列表列表,其中包含了所有可能的方法來獲取列表中的每個列表的一個元素(例如sequence [[1,2],[3,4]]返回[[1,3],[1,4],[2,3],[2,4]])。

+3

在此延伸。根據mapM的定義,將給定示例應用於序列的類型: sequence ::(Monad m)=> [m a]→m [a] 。(0,1,2)=序列(map(\ x→[x])[0,1,2])=序列[[0],[1] ,[2]] = [[0,1,2]] – 2010-06-29 02:02:28

+1

Matthew S:您的評論非常有幫助,謝謝。 – titaniumdecoy 2010-06-29 06:36:18

10

可能值得一提的是,這兩個片段不是「類似的」,你不應該期待相關的結果。特別地,

地圖 '一元' 版本(\ X - > [X])[0,1,2]

MAPM(\ X - > return [x])[0,1,2]

請注意額外的return。通常,return (map f x)mapM (return . f) x相同。

這是因爲對於列表monad,x >>= f'將'f應用到x'的結果'變平。當您忘記return時,應用\x -> [x]的結果正在被放平。有額外的return可以取消額外的展平。