2011-11-23 41 views
22

Tôi đang bối rối. Tôi có thể viết điều này:Folding, thành phần chức năng, monads, và laziness, oh my?

import Control.Monad 

main = print $ head $ (foldr (.) id [f, g]) [3] 
    where f = (1:) 
     g = undefined 

và đầu ra là 1. Có ý nghĩa, vì nó làm giảm tới:

main = print $ head $ ((1:) . undefined . id) [3] 
main = print $ head $ (1:) ((undefined . id) [3]) 
main = print $ head $ 1 : ((undefined . id) [3]) 
main = print $ 1 

Nhưng nếu tôi sử dụng một kỹ thuật monadic mơ hồ tương tự, nó không hoạt động giống nhau:

import Control.Monad 

main = print $ (foldr (<=<) return [f, g]) 3 
    where f = const Nothing 
     g = undefined 

này chạm prelude.Undefined. Đó là kỳ quặc, bởi vì tôi mong chờ nó giảm:

main = print $ ((const Nothing) <=< undefined <=< return) 3 
main = print $ return 3 >>= undefined >>= (\_ -> Nothing) 
main = print $ Nothing -- nope! instead, undefined makes this blow up 

Tuy nhiên, lật thứ tự của phần:

import Control.Monad 

main = print $ (foldr (>=>) return [f, g]) 3 
    where f = const Nothing 
     g = undefined 

không hoàn thành dự kiến ​​ngắn mạch và tạo ra Nothing.

main = print $ (const Nothing >=> undefined >=> return) 3 
main = print $ (const Nothing 3) >>= undefined >>= return 
main = print $ Nothing >>= undefined >>= return 
main = print $ Nothing 

Tôi cho rằng so sánh hai phương pháp có thể đã so sánh táo và cam, nhưng bạn có thể giải thích sự khác biệt không? Tôi nghĩ rằng f <=< g là tương tự monadic để f . g, nhưng họ dường như không giống như tôi nghĩ. Bạn có thể giải thích lý do tại sao?

Trả lời

20

Tùy thuộc vào bạn đang làm việc với đơn vị nào và cách nhà điều hành (>>=) của nó được xác định.

Trong trường hợp Maybe, (>>=) là nghiêm ngặt trong đối số đầu tiên của nó, như Daniel Fischer giải thích.

Dưới đây là một số kết quả cho một số monads khác.

> :set -XNoMonomorphismRestriction 
> let foo = (const (return 42) <=< undefined <=< return) 3 
> :t foo 
foo :: (Num t, Monad m) => m t 

Bản sắc: Lười biếng.

> Control.Monad.Identity.runIdentity foo 
42 

IO: Nghiêm ngặt.

> foo :: IO Integer 
*** Exception: Prelude.undefined 

Đọc: Lười biếng.

> Control.Monad.Reader.runReader foo "bar" 
42 

Writer: Có cả một lười biếng và một biến thể nghiêm ngặt.

> Control.Monad.Writer.runWriter foo 
(42,()) 
> Control.Monad.Writer.Strict.runWriter foo 
*** Exception: Prelude.undefined 

Nhà nước: cũng có cả một nghiêm ngặt và một phiên bản lười biếng.

> Control.Monad.State.runState foo "bar" 
(42,"*** Exception: Prelude.undefined 
> Control.Monad.State.Strict.runState foo "bar" 
*** Exception: Prelude.undefined 

Cont: Strict.

> Control.Monad.Cont.runCont foo id 
*** Exception: Prelude.undefined 
19

Ràng buộc cho Maybe là nghiêm ngặt trong đối số đầu tiên.

Just v >>= f = f v 
Nothing >>= f = Nothing 

Vì vậy, khi bạn cố gắng

Just v >>= undefined >>= \_ -> Nothing 

bạn nhấn

undefined v >>= \_ -> Nothing 

và thực hiện cần phải tìm hiểu xem undefined vNothing hoặc Just something để xem những phương trình của (>>=) để sử dụng.

Mặt khác,

Nothing >>= undefined 

xác định kết quả mà không nhìn vào đối số thứ hai của (>>=).

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