タイトルが言うように:評価されるユニットを返すHaskell関数にはどのような保証がありますか?そのような場合、いかなる種類の評価も実行する必要はないと考えられ()
ますが、厳密さの明示的な要求が存在しない限り、コンパイラーはそのようなすべての呼び出しを即時値に置き換えることができます。リターン()
またはボトム。
私はこれをGHCiで実験しましたが、逆のことが起こっているようです。つまり、そのような関数は評価されているように見えます。非常に原始的な例は
f :: a -> ()
f _ = undefined
評価f 1
すると、が存在するためにエラーがスローされるundefined
ため、評価が確実に行われます。ただし、評価の深さは明確ではありません。場合によっては、を返す関数へのすべての呼び出しを評価する必要があるほど深くなるように見えることがあり()
ます。例:
g :: [a] -> ()
g [] = ()
g (_:xs) = g xs
このコードは、を指定すると無限にループしg (let x = 1:x in x)
ます。しかしその後
f :: a -> ()
f _ = undefined
h :: a -> ()
h _ = ()
を使用して、をh (f 1)
返すことを示すことができる()
ため、この場合、すべての単位値の部分式が評価されるわけではありません。ここでの一般的なルールは何ですか?
ETA:もちろん私は怠惰について知っています。コンパイラー作成者がこの特定のケースを通常よりもさらに遅延させることができないのはなぜですか。
ETA2:例の要約:GHCは()
他の型とまったく同じように扱われるように見えます。つまり、関数から型に存在する通常の値を返す必要があるかどうかの質問があるかのように見えます。そのような値が1つしかないという事実は、最適化アルゴリズムによって(ab)使用されていないようです。
ETA3:Haskellと言うとき、Haskell-the-H-in-GHCではなく、Haskell-as-the-defined-the-Reportを意味します。私が想像したほど広く共有されていない仮定(「読者の100%による」)であると思われるか、またはより明確な質問を定式化できただろう。それでも、最初はそのような関数が呼び出されることについてどのような保証があるかを尋ねていたため、質問のタイトルを変更したことを後悔しています。
ETA4:この質問は当然のように実行されたように思われ、私はそれを未回答と考えています。(「近い質問」機能を探していましたが、「自分の質問に答える」しか見つかりませんでした。答えられないので、そのルートをたどりませんでした)これは、強力であるが明確ではない「そのような言語に対する保証はない」という答えとして解釈したくなります。私たちが知っているのは、現在のGHC実装はそのような関数の評価をスキップしないということです。
OCamlアプリをHaskellに移植するときに実際の問題に遭遇しました。元のアプリには多くのタイプの相互再帰構造があり、コードはassert_structureN_is_correct
1..6または7でNを呼び出すいくつかの関数を宣言しました。それぞれが構造が正しい場合にユニットを返し、正しくない場合に例外をスローしました。さらに、これらの関数は正当性の条件を分解するため、相互に呼び出されました。Haskellでは、これはEither String
モナドを使用してより適切に処理されるため、私はそれをそのように転記しましたが、理論的な問題としての質問は残りました。すべての入力と返信をありがとう。
f 1
「置き換え」られundefined
ます。
... -> ()
は、1)終了して戻る()
、2)例外/実行時エラーで終了して何も返さない、または3)分岐する(無限再帰)ことができます。GHCは、1)のみが発生する可能性があると想定してコードを最適化しません。f 1
要求された場合、評価をスキップしてリターンしません()
。Haskellのセマンティクスは、それを評価し、1,2,3の間で何が起こるかを確認することです。
()
この質問では、(タイプと値のどちらについても)特別なことは何もありません。() :: ()
たとえば、0 :: Int
どこにでも入れ替えると、同じことがすべて起こります。これらはすべて、遅延評価の古い退屈な結果です。
()
()
undefined
h1::()->() ; h1 () = ()
してみてくださいh2::()->() ; h2 _ = ()
。との両方h1 (f 1)
を実行しh2 (f 1)
、最初の1つだけが要求することを確認し(f 1)
ます。