2015-01-04 16 views
8

Tôi là người học Haskell rất mới. Tôi có một biểu hiện làm việc:Biểu thức tương đương Haskell

do x <- try parseA <|> parseB 
    return x 

mà dường như hoạt động hoàn hảo (Tôi đang sử dụng gói Parsec, nhưng tôi hy vọng câu hỏi này không có gì để làm với chức năng của nó, như xa như tôi biết <|> là một Parsec- toán tử đã được xác định). parseAparseB cả hai đều có loại đơn lẻ Parser Foo, cũng như toàn bộ biểu thức.

Dựa trên những gì tôi đã đọc cho đến nay, có vẻ như điều này sẽ tương đương với

do return (try parseA <|> parseB) 

do return $ try parseA <|> parseB 

nhưng không ai trong số các biên dịch thứ hai, họ phàn nàn của các loại không phù hợp (lỗi phía dưới).

nỗ lực khác của tôi để viết lại này, như

(try parseA <|> parse B) >>= return 

dường như làm việc. Nhưng nếu tôi đã hiểu nhầm điều này, xin hãy nói.

Vì vậy, câu hỏi của tôi là, ai đó có thể giải thích lý do tại sao ba người đầu tiên lại khác nhau. Tôi bối rối vì sao chúng không tương đương. Tôi đang thiếu gì?


lỗi (trong trường hợp này là có liên quan, mặc dù fwiw Tôi không tìm kiếm để 'sửa chữa' mã của tôi - Tôi đã một phiên bản làm việc, tôi đang tìm hiểu làm thế nào các phiên bản khác nhau):

do return (try parseA <|> parseB) 

cho

parse.hs:76:11: 
    Couldn't match expected type ‘Foo’ 
       with actual type ‘Text.Parsec.Prim.ParsecT 
            [Char]() Data.Functor.Identity.Identity Foo’ 

do return $ try parseA <|> parseB 

cho

parse.hs:76:3: 
    Couldn't match type ‘Text.Parsec.Prim.ParsecT 
          [Char]() Data.Functor.Identity.Identity Foo’ 
        with ‘Foo’ 
    Expected type: Parser Foo 
     Actual type: Text.Parsec.Prim.ParsecT 
        String 
        () 
        Data.Functor.Identity.Identity 
        (Text.Parsec.Prim.ParsecT 
         [Char]() Data.Functor.Identity.Identity Foo) 

Trả lời

11

Đỗ Notation Desugaring

Các rules for do notation desugaring ngụ ý rằng

do x <- try parseA <|> parseB 
    return x 

tương đương với

(try parseA <|> parse B) >>= return 

($) so (>>=)

Kể từ là một phiên bản lật của (>>=), cả hai đều tương đương với

return =<< (try parseA <|> parse B) 

Điều này ngụ ý rằng sự khác biệt duy nhất giữa phiên bản đúng của bạn và return $ try parseA <|> parse B là sự khác biệt giữa và ($), có loại là:

($) :: (a -> b) -> a -> b 
(=<<) :: (a -> m b) -> m a -> m b 

Bạn có thể thấy rằng ($) không thay thế cho , nhưng có lẽ bạn cũng có thể thấy rằng chúng hơi giống nhau. Một cách để nhìn vào nó là – và do đó cũng (>>=) – là một loại ứng dụng chức năng áp dụng "chức năng monadic" của loại a -> m b đối với một số đơn nguyên m đến "giá trị monadic" của loại m a đối với một số đơn nguyên m, trong khi ($) là loại ứng dụng chức năng thông thường áp dụng các chức năng loại a -> b cho các giá trị loại a.

Luật Monad

Một trong những monad laws

k >>= return = k 

này ngụ ý rằng

(try parseA <|> parse B) >>= return 

cũng có thể được viết như

try parseA <|> parse B 

có nghĩa là bạn r hình thức ban đầu bằng cách sử dụng ký hiệu cũng có thể được viết theo cách đó.

+4

Cảm ơn bạn, đây là mẹo tôi cần phải hiểu. Các bit khác mà tôi đã mất là <- không chỉ là một nhiệm vụ, nó sẽ loại bỏ Monad và trả về kiểu cơ bản, vì vậy x <- y thì foo x không tương đương với foo y.Tôi đánh giá cao câu trả lời toàn diện, Rein. – Ian

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