More fun with applicative functors

前端 未结 5 623
我在风中等你
我在风中等你 2020-12-28 17:48

Earlier I asked about translating monadic code to use only the applicative functor instance of Parsec. Unfortunately I got several replies which answered the question I lite

5条回答
  •  暖寄归人
    2020-12-28 18:31

    The answers already given are excellent, but there's one small(ish) point I'd like to spell out explicitly, and it has to do with <*, <$ and *>.

    One of the examples was

    do var1 <- parser1
       var2 <- parser2
       var3 <- parser3
       return $ foo var1 var2 var3
    

    which can also be written as foo <$> parser1 <*> parser2 <*> parser3.

    Suppose that the value of var2 is irrelevant for foo - e.g. it's just some separating whitespace. Then it also doesn't make sense to have foo accept this whitespace only to ignore it. In this case foo should have two parameters, not three. Using do-notation, you can write this as:

    do var1 <- parser1
       parser2
       var3 <- parser3
       return $ foo var1 var3
    

    If you wanted to write this using only <$> and <*> it should be something like one of these equivalent expressions:

    (\x _ z -> foo x z) <$> parser1 <*> parser2 <*> parser3
    (\x _ -> foo x) <$> parser1 <*> parser2 <*> parser3
    (\x -> const (foo x)) <$> parser1 <*> parser2 <*> parser3
    (const  . foo) <$> parser1 <*> parser2 <*> parser3
    

    But that's kind of tricky to get right with more arguments!

    However, you can also write foo <$> parser1 <* parser2 <*> parser3. You could call foo the semantic function which is fed the result of parser1 and parser3 while ignoring the result of parser2 in between. The absence of > is meant to be indicative of the ignoring.

    If you wanted to ignore the result of parser1 but use the other two results, you can similarly write foo <$ parser1 <*> parser2 <*> parser3, using <$ instead of <$>.

    I've never found much use for *>, I would normally write id <$ p1 <*> p2 for the parser that ignores the result of p1 and just parses with p2; you could write this as p1 *> p2 but that increases the cognitive load for readers of the code.

    I've learnt this way of thinking just for parsers, but it has later been generalised to Applicatives; but I think this notation comes from the uuparsing library; at least I used it at Utrecht 10+ years ago.

提交回复
热议问题