在最近的answer to a style question中,我写道

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


isCorrect num guess =
  case compare num guess of
    EQ -> putStrLn "You Win!" >> return True
    ...

Martijn有助于建议的替代方法:
main = untilM (isCorrect 42) (read <$> getLine)

EQ -> True <$ putStrLn "You Win!"

使用Control.Applicative的抽象可以使Haskell代码中的哪些常见模式更清晰?有效使用Control.Applicative时应记住哪些有用的经验法则?

最佳答案

回答您的问题有很多话要说,但是,自您提出问题以来,我将提供此“经验法则”。

如果您正在使用do -notation并且您正在排序的表达式[2]中未使用您生成的值[1],则该代码可以转换为应用风格。同样,如果在已排序的表达式中使用一个或多个生成的值,则必须使用Monad,而Applicative的强度不足以实现相同的代码。

例如,让我们看下面的代码:

do a <- e1
   b <- e2
   c <- e3
   return (f a b c)

我们看到,在<-右侧的任何表达式中,都没有出现任何生成的值(abc)。因此,我们可以将其转换为使用应用代码。这是一种可能的转换:
f <$> e1 <*> e2 <*> e3

另一个:
liftA3 f e1 e2 e3

另一方面,以这段代码为例:
do a <- e1
   b <- e2 a
   c <- e3
   return (f b c)

该代码不能使用Applicative [3],因为生成的值a稍后将在理解表达式中使用。这必须使用Monad来获得结果-尝试将其分解为Applicative以了解其原因。

关于此主题还有更多有趣且有用的细节,但是,我只是想给您这个经验法则,您可以略过do -comprehension并很快确定是否可以将其分解为Applicative样式代码。

[1]出现在<-左侧的那些。

[2]出现在<-右侧的表达式。

[3]严格来说,通过排除e2 a,它的一部分可以实现。

关于haskell - 您如何使用Control.Applicative编写更简洁的Haskell?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2104446/

10-11 22:34
查看更多