12

このFAQには、

seq演算子は

seq :: a -> b -> b

x seqyはxを評価し、それがボトムでないことを確認してから、結果を破棄してyを評価します。これは役に立たないように思われるかもしれませんが、yが考慮される前にxが評価されることが保証されていることを意味します。

それはHaskellにとってはひどく素晴らしいことですが、それは

x `seq` f x

評価の費用はx2回支払われます(「結果を破棄する」)?

4

5 に答える 5

18

関数はのseq値を破棄しますがx、値が評価されているため、へのすべての参照xは、未評価のバージョンを指すのではなく、評価されたバージョンを指すように「更新」されxます。したがって、をseq評価して破棄xしても、他のユーザーについても値が評価されているため、x評価が繰り返されることはありません。

于 2012-03-14T17:54:37.900 に答える
12

いいえ、それは計算ではなく、忘れてしまいます。それは計算です-これはキャッシュを強制します。

たとえば、次のコードについて考えてみます。

 let x = 1 + 1
 in x + 1

Haskellは怠惰なので、これはに評価され((1 + 1) + 1)ます。サンクと1の合計を含むサンク。内側のサンクは1プラス1です。

怠惰でない言語であるjavascriptを使用して、これがどのように見えるかを示しましょう。

 function(){
   var x = function(){ return 1 + 1 };
   return x() + 1;
 }

このようにサンクをつなぎ合わせると、スタックオーバーフローが発生する可能性があるため、繰り返し実行seqすると救済されます。

let x = 1 + 1
in x `seq` (x + 1)

これが評価されると言ったとき、私は嘘をついています(2 + 1)が、それはほぼ真実です-残りが発生する前に2の計算が強制的に行われるというだけです(ただし、2はまだ怠惰に計算されます)。

javascriptに戻ります:

 function(){
   var x = function(){ return 1 + 1 };
   return (function(x){
     return x + 1;
   })( x() );
 }
于 2012-03-14T17:54:07.137 に答える
4

私はx一度だけ評価されると信じています(そして、怠惰な操作で一般的であるように、結果は将来の使用のために保持されます)。その振る舞いがseq役に立ちます。

于 2012-03-14T17:57:52.943 に答える
1

もちろんseq、それ自体は何も「評価」しませ。強制順序の依存関係を記録するだけです。強制自体は、パターンマッチングによってトリガーされます。seq x (f x)強制されると、最初にx強制され(結果の値をメモ化)、次にf x強制されます。Haskellの遅延評価は、式の強制の結果を記憶することを意味するため、繰り返しの「評価」(ここでは恐ろしい引用)は実行されません。

「評価」は完全な評価を意味するので、怖い引用符で囲みます。Haskellウィキブックスの言葉で、

「Haskellの値は高度に階層化されています。Haskellの値を「評価する」とは、これらの層のいずれかまで評価することを意味する可能性があります。」

繰り返しになりますseqが、それ自体は何も評価しません。 いかなる状況でもseq x x評価されません。レポートが言っているように見えることとは反対に、は何も評価しません。xseq x (f x)f = id

于 2012-03-15T05:04:29.573 に答える
1

いつでも確認できますunsafePerformIOまたはtrace…</p>

import System.IO.Unsafe (unsafePerformIO)

main = print (x `seq` f (x + x))
  where
    f = (+4)
    x = unsafePerformIO $ print "Batman!" >> return 3
于 2012-03-15T13:27:46.170 に答える