【发布时间】:2015-07-12 22:37:18
【问题描述】:
在调试一个记忆函数时,我发现自己试图找出 Seq.mapi 是否真的在迭代一个序列,所以我用 printfn 调用替换了一个匿名函数,如下所示:
let x = "test" |> Seq.map (fun c -> c |> printfn "%c")
令我惊讶的是,打印到控制台的副作用从未发生过,在 FSI 中它只是返回 val d : seq<unit>。虽然这个结果是正确的,但我预计当map 函数迭代序列时会出现副作用。即,当我将其替换为 Seq.map id 时,它会按预期工作并返回自身。
当我将Seq.map 或Seq.mapi 替换为Seq.iter 或Seq.iteri 时,它实际上会打印出副作用。
现在我认为这是由于序列被延迟评估,并且 F# 在内部创建了一个闭包序列,或者实际上在它被调用之前什么都不做,因为如果我这样做 @987654331 @,它确实打印序列中的所有项目。
【问题讨论】:
-
你认为正确;)
-
您还可以通过添加行
for item in x do ()来说服自己相信它的惰性评估,这将强制它评估项目(并将输出吐到控制台) -
@AdamKewley 另一种说服自己这种行为不是对返回单位的函数的优化的方法是尝试使用不返回单位的函数,如下所示:
let x = "test" |> Seq.map (fun c -> c |> printfn "%c"; (char (int c + 1)).ToString());然后这个let y = String.concat "" x
标签: dictionary f# seq side-effects