你如何使用Control.Applicative来编写更清洁的Haskell?
我写了一个最近对风格问题的回答
main = untilM (isCorrect 42) (read `liftM` getLine) 
和
 isCorrect num guess = case compare num guess of EQ -> putStrLn "You Win!" >> return True ... 
Martijn有用地build议了替代scheme:
 main = untilM (isCorrect 42) (read <$> getLine) EQ -> True <$ putStrLn "You Win!" 
通过使用Control.Applicative抽象,可以使Haskell代码中哪些常见模式变得更清晰? 记住有效使用Control.Applicative的有用的经验法则是什么?
回答你的问题还有很多,但是,既然你问了,我会提供这个“经验法则”。
 如果您正在使用do -notation,并且您所生成的值[1]未在您正在sorting的expression式[2]中使用,那么该代码可以转换为Applicative样式。 同样,如果在sorting的expression式中使用一个或多个生成的值,则必须使用Monad而Applicative的强度不足以实现相同的代码。 
例如,让我们看看下面的代码:
 do a <- e1 b <- e2 c <- e3 return (fabc) 
 我们看到,在<-的右边的expression式中没有任何一个生成的值( a , b , c )出现。 因此,我们可以将其转换为使用Applicative代码。 这是一个可能的转变: 
 f <$> e1 <*> e2 <*> e3 
另一个:
 liftA3 f e1 e2 e3 
另一方面,以这段代码为例:
 do a <- e1 b <- e2 a c <- e3 return (fbc) 
 该代码不能使用Applicative [3],因为生成的值a稍后在理解的expression式中使用。 这必须使用Monad来得到它的结果 – 尝试将其分解到Applicative以得到原因。 
 关于这个问题还有一些有趣的和有用的细节,但是我只是想给你一个这样的经验法则,你可以浏览一个do comprehension,并且很快确定它是否可以被分解到Applicative样式代码中。 
  [1]那些出现在<-的左边。 
  [2]表示出现在<-的右侧。 
  [3]严格来说,其中的一部分可以通过分解e2 a 。 
 基本上,单子也是应用函子[1]。 所以,只要你发现自己使用了liftM , liftM2等,就可以使用<*>来链接计算。 从某种意义上讲,你可以把应用函数看作类似于函数的函数。 纯函数f可以通过执行f <$> x <*> y <*> z来提升。 
与monad相比,applicative仿函数不能有select地运行它的参数。 所有争论的副作用将发生。
 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只输出True ,而y依次输出True和False 。 
[1] Typeclassopedia 。 强烈推荐。
[2] http://www.soi.city.ac.uk/~ross/papers/Applicative.html 。 虽然这是一篇学术论文,但并不难。
[3] http://learnyouahaskell.com/functors-applicative-functors-and-monoids#applicative-functors 。 很好地解释了这笔交易。
  [4] http://book.realworldhaskell.org/read/using-parsec.html#id652399 。 演示如何以一种可应用的方式使用monadic Parsec库。 
请参阅应用函数的基础知识,由Bryan O'Sullivan 提供实际工作 。