4

在 Scala 中,您可以在应用或正常顺序评估之间进行选择,请参阅“<a href="http://omgo.wordpress.com/2010/06/07/scala-call-by-name-vs-call-by-type /" rel="nofollow">Scala call-by-name (=>) vs call-by-type" 例如。

  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像或将其限制为命名函数。

除了显式使用 lambda 函数外,F# 还使用lazy关键字和Lazy<'T>类型提供对惰性求值的支持(即,惰性求值,但缓存结果):

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

仅当第一个参数不为零时,此函数才会评估第二个参数:

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 回答