5

この質問は本質的に GHCi を使用した Haskell プログラムでの無限ループのデバッグの複製です。他の解決策を知りたいのですが、著者は手動で解決しました

(私の特定の問題)

再帰呼び出しを含む矢印コードがあります。

testAVFunctor = proc x -> do
    y <- errorArrow "good error" -< x
    z <- isError -< y
    (passError ||| testAVFunctor) -< trace "value of z" z

errorArrow、再帰的な testAVFunctor を実行しないようにする必要があります。これにより、 isError が を返しLeft (AVError "good error")、ルートを選択しpassErrorて再帰呼び出しをバイパスする必要があります。

非常に奇妙なことは、関数合成のような一般的なサイトに「トレース」呼び出しを挿入すると、プログラムが有限量の出力を発行してからフリーズすることです。無限項展開問題から私が期待するものではありません。(編集1を参照)

誰かが興味を持っている場合は、ここにソースコードをアップロードしました。

編集1

私は正しい場所を探していませんでした (ソースを見たい場合は、明らかにavEitherがループしていたようです)。私がそこにたどり着いた方法は、バイナリをコンパイルして gdb を実行することでした:

  • gdb メイン
  • r (コードを実行)
  • Ctrl+C (割り込み送信) . バックトレースは役に立たないだろうが、できることは当たっている
  • s (ステップ) . 次に、Enter キーを押したままにします。多くのメソッド名が飛び交うはずです。そのうちの 1 つが認識されることを願っています。

ghc フラグ-O0を付けてコンパイルすると、最適化を無効にすることができます。これにより、より多くのメソッド名が明らかになります。

編集3

どうやら、proc x -> do上記のブロックによってコードがコンビネータを生成し、AVFunctor.arrリフティング メソッドを呼び出していたようです。トップレベル関数を次のように書き換えると

testAVFunctor = errorArrow "good error" >>>
    isError >>> (passError ||| testAVFunctor)

その後、すべて正常に動作します。ガローを学び、使用してみる時が来たと思います(ここバークレーの大学院生による)。

経験からの私の一般的なポイントは、ghci のデバッグがイライラする可能性があるということです。たとえば、ローカル変数として show の引数を作成することはfできAVFunctor.arrましたが、そこから非常に有益なものを取得することはできません。

> :i f
f :: b -> c     -- <no location info>

修正後のソースコードはこちら

4

1 に答える 1

3

の意味は矢印に(|||)依存し、矢印testAVFunctorの無限のオブジェクトであることに注意してください。

testAVFunctor = proc x -> do
    ...
    (passError ||| proc x -> do
                       ...
                       (passError ||| proc x -> ...) -< trace "value of z" z)
        -< trace "value of z" z

あなたがそれを知っていたかどうかはわかりません。の定義(|||)(定義がない場合はleft) を調べて、無限項を処理できるかどうかを確認します。また、チェックしてください(>>>)(ええと、(.)現代のバージョンではそう思います)。コンビネータが厳密でないことを確認してください。そうすると、無限項が発散します。これには、パターンをより怠惰にすることが含まれる場合があります~(矢印を使用するときは、これを何度も行う必要がありました)。あなたが目にしている振る舞いは、コンビネータの 1 つで厳しすぎることが原因である可能性があります。そのため、何らかの出力を与えるのに「十分」に評価されますが、後でスタックします。

幸運を。あなたは Haskell の深い繊細さの中にいます。

于 2011-05-01T05:59:32.347 に答える