2013-02-27 28 views
18

OK, vì vậy tôi biết loại lớp học Applicative chứa gì và tại sao lại hữu ích. Nhưng tôi không thể quấn bộ não của tôi xung quanh cách bạn sử dụng nó trong một ví dụ không tầm thường.Dịch từ đơn lẻ sang ứng dụng

Xem xét, ví dụ, sau đây khá đơn giản phân tích cú pháp Parsec:

integer :: Parser Integer 
integer = do 
    many1 space 
    ds <- many1 digit 
    return $ read ds 

Bây giờ làm thế nào heck bạn sẽ viết rằng nếu không sử dụng các ví dụ Monad cho Parser? Rất nhiều người cho rằng điều này có thể được thực hiện và là một ý tưởng tốt, nhưng tôi không thể tìm ra chính xác như thế nào.

Trả lời

11
integer :: Parser Integer 
integer = read <$> (many1 space *> many1 digit) 

Hoặc

integer = const read <$> many1 space <*> many1 digit 

Cho dù bạn nghĩ rằng một trong hai trong số này là dễ đọc hơn là tùy thuộc vào bạn.

+0

Tại sao 'const'? – MathematicalOrchid

+1

Chúng ta muốn bỏ qua giá trị (nhưng không phải là hiệu ứng) của 'many1 space', và áp dụng' read' cho giá trị 'many1 digit'. (Xin lỗi, tôi vừa vào, trễ rồi, tôi mệt rồi: Tôi đang chơi nhanh và lỏng lẻo với thuật ngữ.) Nếu bạn tưởng tượng 's' và' d' đại diện cho giá trị của 'many1 space' và' tương ứng với 1 chữ số, sau đó giá trị (bỏ qua hiệu ứng) của 'const đọc <$> many1 space <*> many1 digit' là' const read sd' = 'read d'. – dave4420

38

Tôi muốn viết

integer :: Parser Integer 
integer = read <$ many1 space <*> many1 digit 

Có một loạt các kết trái (như ứng dụng) phân tích cú pháp xây dựng các nhà khai thác <$>, <*>, <$, <*. Điều ở phía xa bên trái phải là hàm thuần túy mà tập hợp giá trị kết quả từ các giá trị thành phần. Điều bên phải của mỗi nhà điều hành phải là một trình phân tích cú pháp, chung cho các thành phần của ngữ pháp từ trái sang phải. Toán tử nào sử dụng tùy thuộc vào hai lựa chọn, như sau.

the thing to the right is signal/noise 
    _________________________    
    the thing to the left is \   
          +------------------- 
        pure/| <$>  <$ 
        a parser | <*>  <* 

Vì vậy, sau khi chọn read :: String -> Integer như chức năng thuần túy mà sẽ cung cấp những ngữ nghĩa của bộ phân tích, chúng ta có thể phân loại các không gian hàng đầu là "tiếng ồn" và loạt các chữ số là "tín hiệu", do đó

read <$ many1 space <*> many1 digit 
(..) (.........)  (.........) 
pure noise parser  | 
(.................)  | 
    parser    signal parser 
(.................................) 
        parser 

Bạn có thể kết hợp nhiều khả năng với

p1 <|> ... <|> pn 

và bất khả nhanh với

empty 

Ít khi cần thiết để đặt tên các thành phần trong trình phân tích cú pháp và mã kết quả trông giống như ngữ pháp có ngữ nghĩa bổ sung.

+8

Wow, tôi biết về '<$', nhưng tôi chỉ sử dụng nó nếu thứ bên trái của nó là một hằng số và bên phải là một giá trị đơn giản ... Tôi chưa bao giờ nghĩ về điều gì sẽ xảy ra nếu tôi đặt một hàm bên trái: P Nice trick –

7

dụ của bạn có thể dần dần viết lại mẫu mà giống như rõ ràng hơn một applicative:

do 
    many1 space 
    ds <- many1 digit 
    return $ read ds 
  1. định nghĩa của do ký hiệu:

    many1 space >> (many1 digit >>= \ds -> return $ read ds) 
    
  2. định nghĩa của $:

    many1 space >> (many1 digit >>= \ds -> return (read ds)) 
    
  3. định nghĩa của .:

    many1 space >> (many1 digit >>= (return . read)) 
    
  4. đơn nguyên 3 luật (associativity):

    (many1 space >> many1 digit) >>= (return . read) 
    
  5. định nghĩa của liftM (trong do ký hiệu phi):

    liftM read (many1 space >> many1 digit) 
    

Đây là (hoặc nên, nếu tôi đã không sai lầm :)) giống hệt nhau trong hành vi ví dụ của bạn.

Bây giờ, nếu bạn thay thế liftM với fmap với <$>, và >> với *>, bạn sẽ có được applicative:

read <$> (many1 space *> many1 digit) 

Đây là hợp lệ vì liftM, fmap, và <$> thường coi là từ đồng nghĩa, như là >>*>.

Tất cả đều hoạt động và chúng tôi có thể làm điều này vì ví dụ ban đầu không sử dụng kết quả của bất kỳ trình phân tích cú pháp nào để tạo trình phân tích cú pháp sau.

+0

Cool! Một cách khác để viết 'đọc <$ many1 không gian <*> many1 digit'. :) Câu cuối cùng là rất quan trọng. Điều đó có nghĩa là phong cách này tương ứng với ngữ pháp không có ngữ cảnh, và các ngữ pháp tổng quát hơn phải được phân tích cú pháp theo kiểu monadic? –

+0

@WillNess Tôi không phải là một chuyên gia về điều này, nhưng tôi tin rằng đó là trường hợp. –

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