F# 理解循环 vars 可变?

F# comprehension loop vars mutable?

提问人:user1443098 提问时间:5/6/2017 更新时间:5/6/2017 访问量:327

问:

例如,在列表组合中,使用的变量是否是与 let stmt 中状态相同的实变量?如果是这样,它实际上是可变的,对吧?每次循环时,它都会绑定到一个新东西,对吧?

变量 f# 列表推导式 可变

评论


答:

7赞 TheInnerLight 5/6/2017 #1

不,它不是一个可变变量。我们可以通过创建函数来看到这一点,我们稍后会调用这些函数来打印它。

观察:

let printIs = [for i in 1..10 do yield fun () -> printf "%i " i]
printIs |> List.iter (fun f -> f())

这将返回:

1 2 3 4 5 6 7 8 9 10

请注意,每个 1..10 值都是打印的,因此不能是可变变量,因为如果是,则在循环完成后将始终具有该值。实际上,该符号在列表推导的每一步中都引用了不同的不可变值。ii10i


如果我尝试使用实际的可变变量来执行此操作,我会得到不同的行为:x

let mutable x = 1
let printIs2 = 
    [for i in 1..10 do 
        x <- i
        yield fun () -> printf "%i " x]
printIs2 |> List.iter (fun f -> f())

这将返回:

10 10 10 10 10 10 10 10 10 10

评论

0赞 user1443098 5/6/2017
但是你循环中的“i”会变异,不是吗?它依次采用值 1 到 10。
0赞 TheInnerLight 5/6/2017
@user1443098 不,它不会变异。如果它确实发生了变异,它的行为将类似于第二个示例,并且每次都打印,因为我们在循环完成后打印值。相反,这告诉你,在列表推导的每一步中都引用了不同的不可变值。10i
0赞 user1443098 5/6/2017
啊!这就是我所缺少的一点!所以,“我指的是一个不同的不可变值”非常感谢!
0赞 user1443098 5/7/2017
我发现有趣的是,Python 中的等效代码会产生不同的结果:确实打印了 10 个 10。但那是因为 Python 的后期绑定行为,IIUC,当调用 lambda 时,i 的值为 10。printIs = [lambda : print (i) for i in range(1,11)] ;for f in printIs: f()
1赞 Tomasz Maczyński 5/7/2017
不错的答案。顺便说一句:在 C# 中,绑定在 foreach 循环中的变量存在很多混淆,这导致了 C# 版本 5 的重大更改。问题并不相同,但性质非常相似。