在 F# 中的 for 循环中,'->' 和 'do' 之间有什么区别

Tho*_*mas 5 f#

我可以做这个:

[ for i in 0 .. 5 -> i ]
Run Code Online (Sandbox Code Playgroud)

或者

[ for i in 0 .. 5 do i ]
Run Code Online (Sandbox Code Playgroud)

但是,虽然我可以这样做:

[ for i in 0 .. 5 do yield! [i * 4; i] ]
Run Code Online (Sandbox Code Playgroud)

我不能这样做:

[ for i in 0 .. 5 -> yield! [i * 4; i] ]
Run Code Online (Sandbox Code Playgroud)

这是为什么?两者如何区别对待?

Tom*_*cek 10

这非常棘手,因为这里有一些 F# 隐式执行的操作。

首先,->语法实际上只是 的快捷方式do yield,因此以下翻译为:

  [ for i in 0 .. 5 -> i ] 
= [ for i in 0 .. 5 do yield i ]
Run Code Online (Sandbox Code Playgroud)

这解释了为什么你不能这样做,-> yield!因为翻译会导致:

  [ for i in 0 .. 5 -> yield! [i * 4; i] ]
= [ for i in 0 .. 5 do yield (yield! [i * 4; i]) ]
Run Code Online (Sandbox Code Playgroud)

你会yield!嵌套在里面yield,这是没有意义的。

第二个棘手的事情是使用 just 的语法do。这是 F# 中最近的一个变化,它使编写列表生成器变得更容易(这对于构造 HTML 树之类的特定领域语言来说非常棒)——编译器隐式插入,yield因此代码转换为:

  [ for i in 0 .. 5 do i ]
= [ for i in 0 .. 5 do yield i ]
Run Code Online (Sandbox Code Playgroud)

有趣的是,这也适用于多个产量:

  [ for i in 0 .. 5 do 
      i
      i*10 ]

= [ for i in 0 .. 5 do 
      yield i 
      yield i*10 ]
Run Code Online (Sandbox Code Playgroud)

这是->和之间的另一个区别do。使用->,您只能产生一件事。使用do,您可以产生多种结果。

我想->现在几乎没有理由使用。这是在隐式之前的语言中yield,因此它在 F# 的早期版本中很有用。当do事情变得如此简单时,您可能不再需要它了。