2012-04-18 25 views
6

Nói rằng tôi đã viết những mảnh Amazin mã sau đây:"<-" và giá trị đi kèm

func = do 
    a <- Just 5 
    return a 

Nó khá vô nghĩa, tôi biết. Tại đây, a5func trả lại Just 5.

Bây giờ tôi viết lại tuyệt vời chức năng (chưa vô nghĩa) của tôi:

func' = do 
    a <- Nothing 
    return a 

Hàm này trả Nothing, nhưng những gì heck là a? Không có gì để trích xuất từ ​​một giá trị Nothing là, tuy nhiên chương trình không rên rỉ khi tôi làm điều gì đó như thế này:

func'' = do 
    a <- Nothing 
    b <- Just 5 
    return $ a+b 

tôi chỉ có một thời gian khó khăn khi nhìn thấy những gì thực sự xảy ra. a là gì? Nói cách khác: <-thực sự làm gì? Nói nó "chiết xuất giá trị từ bên phải và liên kết nó với phía bên trái" rõ ràng là đơn giản hóa nó. Tôi không nhận được gì?

Cảm ơn :)

+1

'<-' dịch thành' >> = '. Trong trường hợp 'Maybe' monad, nếu đối số đầu tiên (tức là phần bên phải' <-') là 'Nothing', không có gì khác được đánh giá và' >> = 'chỉ trả về' Nothing'. Vì vậy, để trả lời câu hỏi của bạn: việc thực hiện thậm chí không _reach_ 'a'. – Vitus

+0

Suy nghĩ về monads là container, do-notation cho phép bạn gán nhãn cho các giá trị (nếu có) bên trong các monads, và sau đó xác định các hàm để áp dụng cho các giá trị đó. Nhưng việc khai thác là một ảo ảnh - các hàm được áp dụng _inside monad_ (sử dụng '>> =') bởi vì không có cách tổng quát nào để trích xuất một giá trị từ một đơn nguyên. Lưu ý cách bạn kết thúc mọi khối do bằng cách đặt kết quả _back vào monad_, thường sử dụng 'return'. Bạn không bao giờ thực sự có một biến 'a' bằng 5. – Nefrubyr

Trả lời

11

Hãy thử và desugar ghi chú của ví dụ cuối cùng.

func'' = Nothing >>= (\a -> Just 5 >>= (\b -> return $ a+b)) 

Bây giờ, hãy xem cách >> = được xác định cho Có thể. Đó là trong Prelude:

instance Monad Maybe where 
    (Just x) >>= k = k x 
    Nothing >>= k = Nothing 
    return   = Just 
    fail s   = Nothing 

Vì vậy Nothing >>= foo đơn giản Nothing

+0

Cảm ơn bạn :) Tôi đoán tôi không phải là rất tốt tại desugaring do-notation ... – Undreren

+1

Mọi foo <- bar sau thanh chương trình >> = (\ foo -> ...). Bây giờ bạn cũng có thể thấy lý do tại sao phải có một biểu thức ở cuối mỗi khối, hoặc một trong những biểu thức lambda (có thể lồng nhau) sẽ có một thân hàm rỗng. Có lẽ liên kết này sẽ giúp: http://book.realworldhaskell.org/read/monads.html#monads.do – Sarah

5

là Chúng ta hãy nhìn vào định nghĩa của Maybe đơn nguyên.

instance Monad Maybe where 
    return = Just 

    Just a >>= f = f a 
    Nothing >>= _ = Nothing 

Và desugar các do -notation trong chức năng của bạn:

func' = 
    Nothing >>= \a -> 
    return a 

Đối số đầu tiên để >>=Nothing và từ định nghĩa trên chúng ta có thể thấy rằng >>= chỉ cần bỏ qua đối số thứ hai. Vì vậy, chúng tôi nhận được:

func' = Nothing 

Vì chức năng \a -> ... không bao giờ được chỉ định, a không bao giờ được chỉ định. Vì vậy, câu trả lời là: a thậm chí không đạt được.


Đối với desugaring do -notation, đây là một phác thảo nhanh chóng như thế nào nó được thực hiện (có một đơn giản tôi đã thực hiện - xử lý fail, mô hình tức là không phù hợp):

do {a; rest} → a >> do rest 

Lưu ý rằng >> thường được triển khai dưới dạng >>=a >>= \_ -> do rest (tức là hàm thứ hai chỉ bỏ qua đối số).

do {p <- a; rest} → a >>= \p -> do rest 

do {let x = a; rest} → let x = a in do rest 

Và cuối cùng:

do {a} = a 

Dưới đây là một ví dụ:

main = do 
    name <- getLine 
    let msg = "Hello " ++ name 
    putStrLn msg 
    putStrLn "Good bye!" 

desugars tới:

main = 
    getLine >>= \name -> 
    let msg = "Hello " ++ name in 
    putStrLn msg >> 
    putStrLn "Good bye!" 

Và t o làm cho nó hoàn chỉnh cho những người tò mò, đây là "đúng" bản dịch của do {p <- a; rest} (lấy trực tiếp từ báo cáo Haskell):

do {pattern <- a; rest} → let ok pattern = do rest 
           ok _  = fail "error message" 
          in a >>= ok 
6

Câu trả lời nằm trong định nghĩa của Monad thể hiện của Maybe:

instance Monad Maybe where 
    (Just x) >>= k  = k x 
    Nothing >>= _  = Nothing 
    (Just _) >> k  = k 
    Nothing >> _  = Nothing 
    return    = Just 

func'' bạn dịch để:

Nothing >>= (\a -> (Just 5 >>= (\b -> return (a+b)))) 

Từ định nghĩa của (>>=) bạn có thể thấy rằng Nothing đầu tiên chỉ được đưa vào kết quả.

2

Nothing là không thực sự "không có gì", nó thực sự là một giá trị có thể có của một cái gì đó trong Maybe đơn nguyên:

data Maybe t = Nothing | Just t 

Đó là, nếu bạn có một cái gì đó kiểu Maybe t đối với một số loại t, nó có thể có giá trị Just x (trong đó x là bất kỳ loại nào t) hoặcNothing; theo nghĩa này, Maybe chỉ cần mở rộng t để có thêm một giá trị có thể, Nothing. (Nó có các tính chất khác bởi vì đó là một monad, nhưng điều đó không thực sự liên quan đến chúng ta ở đây, ngoại trừ các đường cú pháp của do<-.)

1

Hãy lấy ví dụ của bạn:

func = do 
    a <- Just 5 
    return a 

Giống như trong các ngôn ngữ lập trình khác bạn có thể chia thành hai phần tương ứng với "những gì đã được thực hiện cho đến bây giờ" và "những gì vẫn chưa được thực hiện". Ví dụ chúng ta có thể làm cho giờ nghỉ giữa Just 5

a <- ... 
return a 

Trong nhiều ngôn ngữ lập trình phổ biến bạn mong đợi Just 5 được nhồi vào biến a và mã sẽ tiếp tục.

Haskell thực hiện điều gì đó khác biệt. "Phần còn lại của mã" có thể được coi là một hàm mô tả những gì bạn sẽ làm với a nếu bạn có một giá trị để đặt vào nó. Chức năng này sau đó được áp dụng cho Just 5. Nhưng nó không được áp dụng trực tiếp. Nó được áp dụng bằng cách sử dụng bất kỳ định nghĩa nào của >>= áp dụng, tùy thuộc vào loại biểu thức của bạn. Đối với Maybe, >>= được định nghĩa để khi xử lý với Just X, chức năng "phần còn lại của mã" được áp dụng cho X.Nhưng nó cũng được định nghĩa sao cho khi giao dịch với Nothing chức năng "phần còn lại của mã" chỉ bị bỏ qua và trả về Nothing.

Bây giờ chúng ta có thể giải thích mẫu khác của bạn

func'' = do 
    a <- Nothing 
    b <- Just 5 
    return $ a+b 

Nghỉ giải lao nó vào Nothing và:

a <- ... 
    b <- Just 5 
    return $ a+b 

Như tôi đã nói ở trên, khối mã này có thể được coi là một chức năng áp dụng cho một thể giá trị của a. Nhưng nó đang được sử dụng với Nothing và trong trường hợp này >>= được định nghĩa để bỏ qua phần còn lại của mã "" và chỉ trả lại Nothing. Và đó là kết quả bạn có.

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