half
機能は次のとおりです。
そして、それを数回適用できます:
half . half $ 8 => 2
すべてが期待どおりに機能します。 しかし、あなたは、この関数で何が起こっているかをログに記録しておくといいと思いました:
half x = (x `div` 2, " " ++ (show x) ++ "!")
まあ、素晴らしい。 しかし、今度は
half
数回適用したい場合はどうなりますか?
half . half $ 8
これが実現したいことです。
ネタバレ :これは自動的には行われません。 すべてをペンでペイントする必要があります。
finalValue = (val2, log1 ++ log2) where (val1, log1) = half 8 (val2, log2) = half val1
ふう! これは簡潔なものではありません
half . half $ 8
しかし、ログを持つ関数がさらにある場合はどうでしょうか? これは、次のスキームを要求します。値を含むログを返す関数ごとに、これらのログを結合します。 これは副作用であり、モナドのような副作用に強い人はいません!
モナドライター
作家のモナドが
Monad Writerはクールな性格です。 「心配しないで、ログを処理します」と彼女は言います。 「クリーンなコードに戻り、Zeppelinを最大限に活用してください!」
Writerの各インスタンスにはログと戻り値があります。
data Writer wa = Writer { runWriter :: (a, w) }
Writerを使用すると、次のようなコードを記述できます
half 8 >>= half
さて、または、モナドの関数の構成である
<=<
関数を使用して
<=<
を取得できます。
half <=< half $ 8
half . half $ 8
近い
half . half $ 8
half . half $ 8
。 かっこいい!
tell
を使用して、ログに何かを書き込むことができます。 そして、
return
値はこの値をWriterに渡します。 更新された
half
関数は次のとおりです。
half :: Int -> Writer String Int half x = do tell ("I just halved " ++ (show x) ++ "!") return (x `div` 2)
彼女は
Writer
を返します。
また、
runWriter
を使用して、
runWriter
から値を抽出できます。
runWriter $ half 8 => (4, "I just halved 8!")
しかし、最もクールな点は、
>>=
を使用して
half
コールをチェーンできることです。
runWriter $ half 8 >>= half => (2, "I just halved 8!I just halved 4!")
発生することは次のとおりです。
魔法のように
>>=
2つのライターを組み合わせる方法を知っているので、面倒なコードを自分で書く必要はありません! 完全な定義は次のとおりです
>>=
:
以前にまったく同じテンプレートコードを作成しましたが、今では
>>=
がこの責任を引き受けました。 かっこいい! また、値を取得してモナドに入れる
return
関数も使用します。
return val = Writer (val, "")
( 注 :この定義はほぼ正しい。実際、
Writer
モナドでは、行だけでなく、
Monoid
をログとして使用できます。ここで少し簡略化しました。)
Moner Writerありがとう!
モナドリーダー
いくつかの設定を多くの機能に渡したいとします。 モナドリーダーを使用するだけです。
これにより、すべての機能に意味を伝えることができ、伝送メカニズム自体を背後で隠します。 例:
greeter :: Reader String String greeter = do name <- ask return ("hello, " ++ name ++ "!")
greeter
はモナドリーダーを返します。
彼女の定義は次のとおりです。
data Reader ra = Reader { runReader :: r -> a }
リーダーは常に脱走者でした。 ダークホース。 Readerは、関数を処理することができるため、それを考慮すると混乱するため、異なります。 しかし、
runReader
を使用してこの関数を抽出できることは誰もが理解しています。
そして、この関数にいくつかの関数を渡すことができます。この関数は、
greeter
使用されます。
runReader greeter $ "adit" => "hello, adit!"
そのようにして、
>>=
を使用すると、リーダーが返されます。 状態を渡すと、このモナドに含まれるすべての関数に状態が転送されます。
m >>= k = Reader $ \r -> runReader (k (runReader mr)) r
リーダーは常にやや複雑でした。 これは一般的に最高の品質です。
return
は、値を
Reader
入れます。
return a = Reader $ \_ -> a
最後に、
ask
は返された状態を返します。
ask = Reader $ \x -> x
Readerでもっと時間を過ごしたいですか? パンクロックをカットして、より長い例を見てみましょう。
モナド州
State Monadは、読者のより印象的な親友です。
Readerモナドとまったく同じですが、その助けを借りて、読むだけでなく書くこともできます!
State
の定義は次のとおりです。
State sa = State { runState :: s -> (a, s) }
getで状態を
get
か、
put
状態を変更できます。 以下に例を示します。
greeter :: State String String greeter = do name <- get put "tintin" return ("hello, " ++ name ++ "!") runState greeter $ "adit" => ("hello, adit!", "tintin")
いいね Readerが「you-me-not-change」のキャラクターを持っている場合、Stateは、反対に、関係を求め、自分自身を変更する準備ができています。
State
モナドの定義は、モナド
Reader
定義に非常に似ています:
return
:
return a = State $ \s -> (a, s)
>>=
:
m >>= k = State $ \s -> let (a, s') = runState ms in runState (ka) s'
おわりに
作家 読者 州。 今日、Haskellの兵器庫に3つの強力な武器を追加しました。 それらを賢く使用してください。
翻訳者から:この翻訳の品質を改善するのに役立つPMでのコメントに心から感謝します。