カスタム定義の再帰データ型に対する戻り値の定義に問題があります。
データ型は次のとおりです。
データ A a = B a | C (ア・ア) (ア・ア)
ただし、B の値を返すタイミングと C を再帰的に返すタイミングがわからないため、return ステートメントの定義方法がわかりません。
どんな助けでも大歓迎です!
この型のインスタンスを定義する 1 つの方法は、それをフリーモナドMonad
として扱うことです。実際には、これは1 つの二項演算子と、コンストラクターによって埋め込まれた型の値で表される変数を使用した小さな構文になります。これにより、コンストラクタ、埋め込み変数、および置換を実行する演算子が作成されます。A a
C
a
B
return
B
>>=
instance Monad A where
return = B
B x >>= f = f x
C l r >>= f = C (l >>= f) (r >>= f)
(>>= B)
が恒等置換を実行し、置換の構成が連想的であることを理解するのは難しくありません。
このモナドを理解するためのもう 1 つのより「必須の」方法は、コインを裏返す (またはビットストリームを読み取る、またはバイナリ選択のシーケンスに何らかのアクセスを行う) ことができる計算のアイデアをキャプチャすることです。
data Coin = Heads | Tails
コインを裏返すことができる計算は、裏返すのをやめて値になる ( を使用B
) か、コインを裏返してC
コインが上がった場合は 1 つの方法で、 が の場合はHeads
別の方法で続行する ( を使用) 必要がありTails
ます。コインを投げて、出てきたものを教えてくれるモナド演算は
coin :: A Coin
coin = C (B Heads) (B Tails)
の>>=
は、A
コイントス計算の順序付けと見なすことができ、後続の計算の選択が以前の計算によって提供された値に依存することを可能にします。
A
無限のコイン ストリームがある場合は、(並外れた幸運は別として) 次のように、その値に対して任意の計算を実行できるほど幸運でもあります。
data Stream x = x :> Stream x -- actually, I mean "codata"
flipping :: Stream Coin -> A v -> v
flipping _ (B v) = v
flipping (Heads :> cs) (C h t) = flipping cs h
flipping (Tails :> cs) (C h t) = flipping cs t
この種のモナドの一般的なパターンは、値を返すための 1 つのコンストラクター (B
ここ) と、可能な操作の選択と、操作の結果が与えられたときに計算を続行できるさまざまな方法を表す他のコンストラクターを持つことです。ここC
には非再帰的なパラメーターがなく、サブツリーが 2 つあるため、操作は 1 つだけであり、可能な結果は 2 つだけである必要があり、コインを投げることができます。
つまり、変数と 1 つの二項演算子を使用した構文の置換、またはコインを投げる計算の順序付けの方法です。どちらの見方が良いですか?うーん...それらは同じコインの表裏です。
の良い経験則return
は、動作する可能性のある最も単純なものにすることです (もちろん、モナドの法則を満たす任意の定義は問題ありませんが、通常は最小限の構造を持つものが必要です)。return = B
この場合、それは(一致するように a を書きます(>>=)
!) と同じくらい簡単です。
ところで、これはフリーモナドの例です-- 実際、これはドキュメントに記載されている例なので、ドキュメント自体に語らせます。