4

Scala では、適用的評価または通常の順序評価のいずれかを選択できます。 /" rel="nofollow">Scala の名前による呼び出し (=>) と型による呼び出し" の例を参照してください。

  def byName(a: => Unit) = {
    for (i <- 0 until 10) {println(a)}

  }

  def byValue(a: Unit) = {
    for (i <- 0 until 10) {println(a)}

  }

  var i = 1;

  byValue(i = i + 1)
  println(i); // 2

  byName(i = i + 1)
  println(i) // 12

F# でも同じことが可能ですか?

4

2 に答える 2

4

Lee が指摘したように、F# では関数の引数の評価方法を指定できません。これは確かに便利な機能ですが、混乱を招くこともあると思います。たとえば、 のようなファーストクラスの関数があるint -> int場合、型は使用する評価戦略を教えてくれないので、型をより複雑にする必要があります。または、これを名前付き関数に制限します。

lazy明示的にラムダ関数を操作する以外に、F# は次のキーワードとLazy<'T>型を使用して遅延評価 (つまり、遅延評価しますが、結果をキャッシュする) もサポートします。

let foo (a:Lazy<int>) (b:Lazy<int>) = 
  if a.Value = 0 then 0
  else b.Value

この関数は、最初の引数がゼロでない場合にのみ、2 番目の引数を評価します。

foo (lazy (printfn "a"; 0)) (lazy (printfn "b"; 10))   // Prints just 'a'
foo (lazy (printfn "a"; 10)) (lazy (printfn "b"; 10))  // Prints both 'a' and 'b'

これは、関数を使用するよりも構文的に軽量ですが、宣言サイトだけでなく、呼び出しサイトでも明示的な指定が必要です。

于 2013-03-28T13:26:09.963 に答える
3

私の知る限り、これに対する組み込みのサポートはありません。そのため、最も近い方法は、関数で計算を遅らせてエミュレートすることです。

let cnst a b = a
let apply (f: unit -> unit) = Seq.iter (fun i -> printfn "%A" (f())) [1..10]
let byName (f: unit -> unit) = apply (cnst (f()))
let byValue (f: unit -> unit) = apply f

次に、あなたの例は次のようになります。

let i = ref 1
byValue (fun _ -> do i := !i + 1)

printfn "%d" !i

i := 1
byName (fun _ -> do i := !i + 1)
printfn "%d" !i
于 2013-03-28T13:17:58.400 に答える