为什么循环表达式的简单限制为整数范围?

时间:2013-04-16 19:53:47

标签: for-loop f# inline control-flow imperative-programming

根据F#规范(参见§6.5.7),简单for循环以整数(int又名int32又名System.Int32)限制startstop,例如

for i = start to stop do
    // do sth.

我想知道为什么这种类型的for循环的迭代界限必须是int32。为什么不允许uint32int64bigint

我知道序列迭代表达式(for ... in ...)可以迭代任意序列;然而,这需要分配一个迭代器并调用MoveNextCurrent什么不是,因此可能比普通循环效率低得多(增量计数器,比较,条件跳转)。为避免这种情况,您将无法使用while和手动递增循环计数器......

奇怪的是,如果int32表达式包含在序列表达式中,F# 允许非for循环边界,例如

seq { for i = 0I to 10I do
        printfn "%A" i }

所以,我想问题是:是否有一个特殊的原因只允许int32循环?为什么此限制不适用于for表达式中包含的seq循环?

3 个答案:

答案 0 :(得分:7)

我不确定为什么F#不允许int64范围。这听起来像是一个有用的功能...(但我可以理解int是C#中的标准类型,也许F#尝试遵循这种模式。)

至于解决方法,值得补充的是你还可以编写inline高阶函数:

let inline longFor low high f = 
  let rec loop n =
    if n < high then f n; loop (n + 1L)
  loop low

...然后您可以以相当简洁的方式在for范围内表达int64个循环:

longFor 1L 100L (fun n -> 
  <whatever> )

我做了几个实验,似乎F#编译器能够相当合理地优化它(lambda函数是内联的,尾递归loop函数变成while循环)。我不认为这是保证所以您可能需要手动检查高性能代码,但它似乎适用于更简单的示例。

只有一个缺点 - 您将无法使用本地可变变量(let mutable),因为lambda函数无法捕获这些变量。因此,间接ref单元格可能会产生额外成本(但我不确定这是多大的问题)。

答案 1 :(得分:2)

如果你想保留for循环,可以使用for...in循环sequence range operator进行非常简单的解决方法:

for i in 0I .. 10I do
    printfn "%A" i

只要两种类型匹配,范围运算符将接受任何大小的任何整数。例如,以下将编译:

for i in 0 .. 10I do
    printfn "%A" i

答案 2 :(得分:0)

另一种可能的解决方法:

[1L..100L] |&gt; List.iter(有趣的i - &gt; printfn“%i”i)