根据F#的规格(见§6.5.7 ),for循环简单的通过整数界( int
又名int32
又名System.Int32
)限制start
和stop
,如
for i = start to stop do
// do sth.
我不知道为什么需要这种类型的for循环迭代边界是int32
。 为什么不允许uint32
? int64
? bigint
?
我知道该序列迭代表达式( for ... in ...
)可以遍历任意序列; 然而,这需要分配一个迭代,并调用MoveNext
和Current
并没有什么,因此可以大大低效率比普通的循环可能是(增量计数器,比较conditonal跳转)。 为了避免这种情况,你是坚持使用while
和手动递增循环计数器...
奇怪的是,F# 确实允许非int32
循环边界,如果for
表达被包裹在一个序列表达,例如
seq { for i = 0I to 10I do
printfn "%A" i }
所以,我想的问题是:是否有仅允许特定的原因int32
for循环? 而为什么这种限制并不适用于for
包裹在循环seq
的表达?
我不知道为什么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
细胞(但我不知道问题有多大,这是)。
如果你想保持for循环,有一个非常简单的工作,周围用了...在同一个循环序列范围操作 :
for i in 0I .. 10I do
printfn "%A" i
只要这两种类型的匹配范围运营商将接受任何规模的整数。 例如,以下不会编译:
for i in 0 .. 10I do
printfn "%A" i
另一种可能的解决方法:
[1L..100L] |> List.iter(乐趣I - > printfn “%i” 的ⅰ)