2011-07-13 14 views
8

私はちょうどF#を開始していますので、これが基本的であれば親切にしてください。F#レイジー評価と非レイジーの比較

lazyとマークされた関数は一度しか評価されずにキャッシュされることを読んだことがあります。例:実際にそれが呼ばれるたび実行します。このバージョンに比べて

let lazyFunc = lazy (1 + 1) 
let theValue = Lazy.force lazyFunc 

:それに基づいて

let eagerFunc = (1 + 1) 
let theValue = eagerFunc 

は、怠惰行われるすべての機能を必要がありますか?いつあなたはしたくないですか?これは本の資料"Beginning F#"の資料に由来しています。

+0

これはどのバージョンですか?私は遅れて行動しているシーケンスを持っていますが、そのように明白に作成されたシーケンスはありません。私はそれを強制的に完了しようとしています。 – octopusgrabbus

答えて

13

まず第一に、あなたが定義したものがいずれも機能しないことに注意すると便利かもしれません。表現1 + 1

let lazyTwo = lazy (1 + 1) 

let eagerTwo = 1 + 1 

を考えると関係なく、あなたがeagerTwoを使用する回数を複数回評価されないことはないます。違いは1 + 1正確一度場合eagerTwoを定義評価されるが、(その後Valueプロパティがアクセスされる最初の時間を評価し、そしてするlazyTwo使用されると最もでが評価されることですキャッシュして、Valueの使用を再計算する必要はありません)。 lazyTwoValueにアクセスしたことがない場合、その本体1 + 1となります。は評価されません。

通常、F#などの厳密な言語で遅延値を使用すると、大きなメリットはありません。 Valueプロパティにアクセスすると、値がすでに計算されているかどうかを確認する必要があるため、オーバーヘッドはわずかです。値が実際に使用される場合にのみ、高価な計算が行われるため、let lazyValue = lazy someVeryExpensiveCalculationThatMightNotBeNeeded()のようなものを使用すると計算量が減ります。また、そうでなければそうでないアルゴリズムを終了させることもできますが、これはF#の主要な問題ではありません。たとえば、

// throws an exception if x = 0.0 
let eagerDivision x = 
    let oneOverX = 1.0/x 
    if x = 0.0 then 
     printfn "Tried to divide by zero" // too late, this line is never reached 
    else 
     printfn "One over x is: %f" oneOverX 

// succeeds even if x = 0.0, since the quotient is lazily evaluated 
let lazyDivision x = 
    let oneOverX = lazy (1.0/x) 
    if x = 0.0 then 
     printfn "Tried to divide by zero" 
    else 
     printfn "One over x is: %f" oneOverX.Value 
+0

'()'を使用していないのはそれが関数であることを意味していますか?いずれにしても良い点。あなたは正しいです私の例は超簡単です。 – Yuck

+0

@Yuck - カッコは異なるコンテキストで異なることを意味します。あなたが '(1 + 1)'のようにそれらを使うとき、彼らは単にグループ化と優先順位を示す役目をしています。 'let eagerFunc()= ...'を定義していた場合、カッコは 'eagerFunc'が関数であることを示しますが、これはあなたが書いたものとは異なることに注意してください。 – kvb

6

関数の実行に副作用があり、関数が呼び出されるたびに(関数がI/O関数をラップする)副作用を確認することが重要な場合は、怠け者であることは望ましくありません。

も結合させ、そして一度だけ実行されますされ、それらを毎回実行するとvalue--

5

let eagerFunc = (1 + 1)をキャッシュするよりも速くなるように些細な関数があります。 let eagerFunc() = (1 + 1)は、unit(何もない)を受け取り、intを返す関数です。呼び出されるたびに実行されます。ある意味では、すべての関数は怠惰です。つまり、呼び出されたときにのみ実行されます。しかし、lazyキーワード(およびそれが返すSystem.Lazy)は、最大で1回だけ与えられた式/関数を実行します。その後、Valueプロパティを呼び出すと、キャッシュされた結果が返されます。これは、値の計算が高価な場合に便利です。

lazyでは、多くの関数が非決定論的(各呼び出しで異なる結果を返す可能性がある)またはパラメータ化されているため、多くの関数は適切ではありません。もちろん、完全に適用された(各パラメータに値が与えられる)バージョンを使用することは可能ですが、一般的にはばらつきが望まれます。 eagerFunctheValueはタイプintの値であり、lazyFuncはタイプLazy<int>の値である -

関連する問題