2010-06-29 42 views
28

Tôi đang tham gia chương I/O của H Worldell trong thế giới thực. Monads không được thảo luận trong cuốn sách cho 7 chương khác. Đó là để nói, sự hiểu biết của tôi về I/O là, tốt nhất, không đầy đủ.bản đồ so với hành vi của bản đồ

Hiện tại tôi đang cố gắng hiểu chức năng mapM. Như tôi đã hiểu, hàm "thực hiện" từng phần tử trong danh sách phải là "hành động" (IO monad).

Điều gì không có ý nghĩa là this example. Tại sao mapM trả về một kết quả khác với bản đồ cho cùng một đối số?

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

cũng vui vẻ: 'chiều dài (mapM (\\ _-> a) b) == chiều dài a^length b'. Tôi nghĩ. – muhmuhten

Trả lời

18

Theo tôi được biết, chức năng "thực hiện" mỗi phần tử trong danh sách đó phải là một "hành động" (IO đơn nguyên).

Đó là đúng đối với IO, nhưng trong ví dụ mã của bạn bạn không sử dụng các đơn nguyên IO, bạn sử dụng đơn nguyên danh sách (các chức năng bạn cung cấp cho mapM trả về một danh sách ([x]), không phải là một IO).

mapM được định nghĩa là mapM f as = sequence (map f as). Nếu f trả về một IO, điều này có nghĩa là đối với mỗi phần tử trong danh sách nó xây dựng một IO bằng cách áp dụng f cho phần tử. Sau đó nó sẽ chuyển danh sách các IO mà ánh xạ trở về một IO "chứa" một danh sách bằng cách sử dụng trình tự (vì vậy khi bạn thực thi IO, bạn lấy lại một danh sách chứa các giá trị không phải là IO).

Đối với danh sách, điều này có nghĩa là danh sách sẽ tạo danh sách các danh sách bằng cách áp dụng f cho mỗi thành phần của as. Sau đó, nó sử dụng sequence để tạo danh sách các danh sách chứa tất cả các cách có thể để lấy một phần tử của từng danh sách trong danh sách danh sách (ví dụ: sequence [[1,2],[3,4]] trả về [[1,3],[1,4],[2,3],[2,4]]).

+3

Để mở rộng điều này. Trong ánh sáng của định nghĩa của mapM, áp dụng loại trình tự: trình tự :: (Monad m) => [m a] -> m [a] đến ví dụ đã cho. mapM (\ x -> [x]) [0, 1, 2] = chuỗi (bản đồ (\ x -> [x]) [0, 1, 2]) = chuỗi [[0], [1] , [2]] = [[0,1,2]] –

+1

Matthew S: Cảm nhận của bạn rất hữu ích, cảm ơn. – titaniumdecoy

10

Có thể đáng để nói rõ ràng rằng hai đoạn mã này không phải là 'tương tự' và bạn không nên mong đợi kết quả có liên quan. Đặc biệt, một phiên bản 'monadic' của

bản đồ (\ x -> [x]) [0, 1, 2]

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

Lưu ý thêm return.

Nói chung, return (map f x) cũng giống như mapM (return . f) x.

Điều này là do đối với danh sách đơn lẻ, x >>= f 'làm phẳng' kết quả của việc áp dụng f đến x. Khi bạn rời khỏi return kết quả của việc áp dụng \x -> [x] đã được làm phẳng thành kết quả. Có thêm return sẽ loại bỏ sự làm phẳng thêm.

Các vấn đề liên quan