これは、前の質問の answer のフォローアップです。
_a:A
_の各項目_List[A]
_を関数def f(a:A, leftNeighbors:List[A]): B
で_b:B
_にマップし、_List[B]
_を生成する必要があるとします。
当然、リストでmap
を呼び出すだけではなく、リストzipperを使用できます。ジッパーは、リスト内を移動するためのカーソルです。現在の要素(focus
)とその隣接要素へのアクセスを提供します。
これで、f
をdef f'(z:Zipper[A]):B = f(z.focus, z.left)
に置き換えて、この新しい関数_f'
_を_Zipper[A]
_のcobind
メソッドに渡すことができます。
cobind
は次のように機能します。ジッパーを使用して_f'
_を呼び出し、次にジッパーを移動し、newを使用してcalls _f'
_を移動します移動された」ジッパー、ジッパーを再度移動する、などのように...ジッパーがリストの最後に到達するまで続けます。
最後に、cobind
は、タイプ_Zipper[B]
_の新しいジッパーを返します。これはリストに変換できるため、問題は解決されます。
cobind[A](f:Zipper[A] => B):Zipper[B]
とbind[A](f:A => List[B]):List[B]
の対称性に注意してください。そのため、List
はMonad
であり、Zipper
はComonad
です。
理にかなっていますか?
この質問は「未回答」リストの上部に定期的に表示されるため、ここに回答として私のコメントをコピーさせてください-とにかく1年前からそれほど建設的なことは何もありません。
List
も同様に(複数の方法で)コマンドとして表示でき、Zipper
はモナドとしてキャストできます(さまざまな方法で)。違いは、状態マシンにデータを建設的に「追加」することに焦点を当てているのか(それがMonad
インターフェースの概要である)か、それから「破壊的に」状態を「抽出する」のか(Comonad
はします)。
「この理解は理にかなっている」と述べられている質問に答えることは容易ではありません。ある意味ではそうしますが、別の意味ではしません。