在Scala中,您可以选择应用或正常的订单评估,有关示例,请参阅“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#中是否可以相同?
答案 0 :(得分:4)
正如李指出的那样,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'
这在语法上比使用函数更轻量级,但它仍然需要在调用站点上进行明确规范,而不仅仅是在声明站点上。
答案 1 :(得分: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