web-dev-qa-db-ja.com

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 役立つ代替案:

main = untilM (isCorrect 42) (read <$> getLine)

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

Control.Applicative からの抽象化を使用して、Haskellコードのどの一般的なパターンをより明確にすることができますか? Control.Applicativeを効果的に使用するために覚えておくと便利な経験則は何ですか?

60
Greg Bacon

あなたの質問に答えて言うことはたくさんありますが、あなたが尋ねたので、私はこの「経験則」を提供します。

do- notationを使用していて、生成された値[1]がシーケンス処理する式[2]で使用されていない場合、そのコードはApplicativeスタイルに変換できます。同様に、シーケンスされた式で生成された値の1つ以上を使用する場合は、Monadを使用する必要があり、Applicativeは同じコードを実現するのに十分な強度がありません。

たとえば、次のコードを見てみましょう。

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

<-の右側のどの式にも、生成された値(abc)は表示されないことがわかります。したがって、Applicativeコードを使用するように変換できます。考えられる変換の1つを次に示します。

f <$> e1 <*> e2 <*> e3

そして別の:

liftA3 f e1 e2 e3

一方、次のコードを例にとってみましょう。

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

生成された値Applicativeは後で内包表記の式で使用されるため、このコードではa [3]を使用できません。結果を得るには、Monadを使用する必要があります。理由を把握するために、Applicativeに因数分解してみてください。

このテーマについては、さらに興味深く有用な詳細がいくつかありますが、この経験則を提供することを目的としています。これにより、do-の理解をざっと見て、Applicativeスタイルコードに組み込むことができるかどうかをすばやく判断できます。

[1] <-の左側に表示されるもの。

[2] <-の右側に表示される式。

[3]厳密に言えば、その一部はe2 aを因数分解することで可能です。

48
Tony Morris

基本的に、モナドは適用可能な関手でもあります[1]。したがって、liftMliftM2などを使用していることに気付いたときはいつでも、<*>を使用して計算を連鎖させることができます。ある意味で、適用可能なファンクターは関数に類似していると考えることができます。純粋関数fは、f <$> x <*> y <*> zを実行することで解除できます。

モナドと比較して、適用可能なファンクターはその引数を選択的に実行できません。すべての議論の副作用が起こります。

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")

xTrueのみを出力しますが、yTrueFalseを順番に出力します。

[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 。モナドのParsecライブラリを適用可能な方法で使用する方法を示します。

44
Wei Hu
10
Greg Bacon