31

残りのアロー機構にはかなり慣れましたが、ループがどのように機能するかわかりません。それは私には魔法のように思えますが、それは私の理解にとって悪いことです. mfixも理解できません。orブロックで使用recするコードを見ると、混乱します。通常のモナド コードまたはアロー コードを使用すると、計算をステップ実行して、頭の中で何が起こっているかの操作上の図を保持できます。になったら、どの写真を残せばいいのかわからない!私は立ち往生し、そのようなコードについて推論することはできません.procdorec

私が理解しようとしている例は、矢印に関するロス・パターソンの論文、回路に関するものです。

counter :: ArrowCircuit a => a Bool Int
counter = proc reset -> do
        rec     output <- returnA -< if reset then 0 else next
                next <- delay 0 -< output+1
        returnA -< output

この例を理解すれば、ループ全般を理解できるようになり、mfix を理解する上で非常に役立つと思います。彼らは本質的に私には同じように感じますが、おそらく私が見逃している微妙な点がありますか? とにかく、私が本当に賞賛したいのは、そのようなコード片の操作図です。これにより、「通常の」コードのように頭の中でステップスルーできます。

編集:Pigworkerの回答のおかげで、recなどの要求が満たされることについて考え始めました。例を挙げるcounterと、 rec ブロックの最初の行は という値を要求しますoutputoutputこれは、操作上、ボックスを作成し、ラベルを付け、 rec ブロックにそのボックスを埋めるように依頼することを想像しています。そのボックスを満たすために、returnA に値をフィードしますが、その値自体は と呼ばれる別の値を要求しますnext。この値を使用するには、rec ブロックの別の行で要求する必要がありますが、今のところ、rec ブロックのどこで要求されているかは問題ではありません

次の行に移動すると、 というラベルの付いたボックスが見つかり、next別の計算でそれを満たすように要求します。さて、この計算には最初のボックスが必要です! ボックスを指定しますが、その中には値がありません。したがって、この計算で の内容が要求されるとoutput、無限ループに陥ります。さいわい、delay はボックスを受け取りますが、ボックスの中を見ずに値を生成します。これで塗りつぶさnextれ、塗りつぶしが可能になりますoutput。これでoutput、この回路の次の入力が処理されると、前のボックスはその値を持ち、次の 、したがってoutput次の を生成するために要求される準備が整います。nextoutput

それはどのように聞こえますか?

4

1 に答える 1

27

このコードでは、重要な要素はブロックdelay 0内の矢印です。recそれがどのように機能するかを理解するには、値が時間とともに変化し、スライスに切り刻まれていると考えると役立ちます。私はスライスを「日」と考えています。ブロックは、rec毎日の計算がどのように機能するかを説明します。因果順序ではなくで整理されていますが、注意すれば因果関係を追跡できます。重要なことは、毎日の仕事が未来ではなく過去に依存していることを (の助けなしに) 確認する必要があることです。1 日は、その点で時間を稼いでくれます。入力信号を 1 日後にシフトし、値 0 を与えることで最初の日を処理します。遅延の入力信号は「明日」です。delay 0next

rec     output <- returnA -< if reset then 0 else next
        next <- delay 0 -< output+1

したがって、矢印とその出力を見ると、今日 . インプットを見ると、今日の価値観に依存しています。タイムトラベルなしで、これらの入力からそれらの出力を提供できることは明らかです。0 にしない限り、今日の数字です。明日、番号は今日の後継です。したがって、今日の値は昨日から取得されます。ただし、昨日が存在しない場合は 0 です。output next resetnextoutputnextresetnextoutputnext

下位レベルでは、Haskell の遅延により、このセットアップ全体が機能します。Haskell は需要駆動型の戦略によって計算するため、因果関係を尊重するタスクの順序があれば、Haskell はそれを見つけます。ここでは、そのdelayような順序を確立します。

ただし、Haskell の型システムは、そのような順序が存在することを保証するのにほとんど役に立たないことに注意してください。まったくナンセンスなループを自由に使用できます。したがって、あなたの質問は些細なことではありません。このようなプログラムを読んだり書いたりするたびに、「これはどうやって動くのだろうか?」と考える必要があります。delay計算可能な場合にのみ情報が要求されるように、(または同様の) 情報が適切に使用されていることを確認する必要があります。特にコンストラクタに注意してください(:)遅延のように振る舞うこともできます: リスト全体が明らかに与えられた場合、リストの末尾を計算することは珍しいことではありません (ただし、先頭だけを調べるように注意してください)。命令型プログラミングとは異なり、怠惰な関数型スタイルでは、一連のイベント以外の概念に基づいてコードを編成できますが、それは時間のより微妙な認識を必要とする自由です。

于 2011-08-08T09:49:15.833 に答える