How do you use Control.Applicative to write cleaner Haskell?

后端 未结 3 1236
野趣味
野趣味 2020-12-12 10:49

In a recent answer to a style question, I wrote

main = untilM (isCorrect 42) (read `liftM` getLine)

and

isCorrect num guess         


        
3条回答
  •  生来不讨喜
    2020-12-12 11:51

    Basically, monads are also applicative functors [1]. So, whenever you find yourself using liftM, liftM2, etc., you could chain the computation together using <*>. In some sense, you can think of applicative functors as analogous to functions. A pure function f can be lifted by doing f <$> x <*> y <*> z.

    Compared to monads, applicative functors cannot run its arguments selectively. The side effects of all the arguments will take place.

    import Control.Applicative
    
    ifte condition trueClause falseClause = do
      c <- condition
      if c then trueClause else falseClause
    
    x = ifte (return True) (putStrLn "True") (putStrLn "False")
    
    ifte' condition trueClause falseClause = 
      if condition then trueClause else falseClause
    
    y = ifte' <$> (pure True) <*> (putStrLn "True") <*> (putStrLn "False")
    

    x only outputs True, whereas y outputs True and False sequentially.

    [1] The Typeclassopedia. Highly recommended.

    [2] http://www.soi.city.ac.uk/~ross/papers/Applicative.html. Although this is an academic paper, it's not hard to follow.

    [3] http://learnyouahaskell.com/functors-applicative-functors-and-monoids#applicative-functors. Explains the deal very well.

    [4] http://book.realworldhaskell.org/read/using-parsec.html#id652399. Shows how the monadic Parsec library can also be used in an applicative way.

提交回复
热议问题