2010-06-29 10 views
28

Jestem na rozdziale I/O realnego świata Haskella. Monady nie są omawiane w książce przez kolejne 7 rozdziałów. Co oznacza, że ​​moje rozumienie I/O jest w najlepszym przypadku niekompletne.map versus mapM behavior

Teraz próbuję zrozumieć funkcję mapM. Jak rozumiem, funkcja "wykonuje" każdy element na liście, który musi być "akcją" (IO monada).

To, co nie ma sensu, to this example. Dlaczego mapM zwraca inny wynik niż mapa dla tych samych argumentów?

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

również zabawa: 'length (mapM (\\ _-> a) b) == length a^length b'. Myślę. – muhmuhten

Odpowiedz

18

Jak rozumiem, funkcja „wykonuje” każdy element na liście, która musi być „działanie” (IO monada).

To prawda do IO, ale w przykładzie kodu nie używać Monada IO, należy użyć Monada liście (funkcja dajesz mapM zwraca listę ([x]), a nie IO).

mapM jest zdefiniowany jako mapM f as = sequence (map f as). Jeśli f zwraca OI, oznacza to, że dla każdego elementu na liście konstruuje IO, stosując f do elementu. Następnie zmienia listę IO, która odwzorowuje mapę na IO "zawiera" listę używając sekwencji (więc gdy wykonasz IO, otrzymasz listę zawierającą wartości inne niż IO).

W przypadku list oznacza to, że tworzy listę list przez zastosowanie f do każdego elementu z as. Następnie używa sequence, aby utworzyć listę list, która zawiera wszystkie możliwe sposoby pobrania jednego elementu z każdej listy na liście list (np. sequence [[1,2],[3,4]] zwraca [[1,3],[1,4],[2,3],[2,4]]).

+3

Aby przedłużyć na tym. W świetle definicji mapy M zastosuj typ sekwencji: sekwencja :: (Monad m) => [m a] -> m [a] do podanego przykładu. mapM (\ x -> [x]) [0, 1, 2] = sekwencja (mapa (\ x -> [x]) [0, 1, 2]) = sekwencja [[0], [1] , [2]] = [[0,1,2]] –

+1

Matthew S: Twój komentarz był bardzo pomocny, dzięki. – titaniumdecoy

10

Warto chyba wyjaśnić, że te dwa fragmenty nie są "analogiczne" i nie należy spodziewać się podobnych wyników. W szczególności, 'monadycznego' wersja

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

jest

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

Uwaga na dodatkowe return.

Ogólnie rzecz biorąc, return (map f x) jest tożsamy ​​z mapM (return . f) x.

Dzieje się tak dlatego, że dla monady listy, x >>= f "spłaszcza się" w wyniku zastosowania f do x. Gdy pominięto return, wyniki zastosowania \x -> [x] zostały spłaszczone w wyniku. Posiadanie dodatkowego return anuluje dodatkowe spłaszczanie.