F# 对于在F中给出错误类型的二维数组中的循环#

F# 对于在F中给出错误类型的二维数组中的循环#,f#,type-inference,F#,Type Inference,我怀疑我在这里遗漏了一些非常明显的东西,但这不起作用: let t = Array2D.create 1 1 1.0 for x in t do printfn "%f" x;; 它失败了 错误FS0001:类型“obj”与使用printf样式格式字符串产生的任何类型float、float32、decimal不兼容 有趣的是,使用printf“%A”或“%O”打印预期值,这向我表明问题在于类型推断 1D数组的相应代码工作正常 let t = Array.create 1 1.0 for x i

我怀疑我在这里遗漏了一些非常明显的东西,但这不起作用:

let t = Array2D.create 1 1 1.0
for x in t do printfn "%f" x;;
它失败了

错误FS0001:类型“obj”与使用printf样式格式字符串产生的任何类型float、float32、decimal不兼容

有趣的是,使用
printf“%A”
“%O”
打印预期值,这向我表明问题在于类型推断

1D数组的相应代码工作正常

let t = Array.create 1 1.0
for x in t do printfn "%f" x;;

作为参考,这是运行在.NET中最新mono上的2.0版(交互式和编译器),1D数组隐式实现了IList,这意味着它还实现了(通过继承)
IEnumerable
。所以,当你跑步时:

let t = Array.create 1 1.0
for x in t do printfn "%f" x;;
F#编译器从
t
发出代码,从中获取
IEnumerable
seq
)的实现,然后对其进行迭代。由于它能够从数组中获取
IEnumerable
x
将具有类型
T

另一方面,多维数组(2d、3d等)只实现
IEnumerable
(而不是
IEnumerable
),因此F#编译器将
x
的类型推断为
System.Object
(或
obj
,在F#中)

有两种解决方案可满足您的需求:

在打印之前,在循环中强制转换每个值:

for x in t do printfn "%f" (x :?> float);;
for x in (Seq.cast<float> t) do printfn "%f" x;;
或者,使用Seq.cast创建并迭代强类型枚举数:

for x in t do printfn "%f" (x :?> float);;
for x in (Seq.cast<float> t) do printfn "%f" x;;
对于x in(Seq.cast t)不打印“%f”x;;

正如杰克指出的,这是一个问题。一个简单的解决方案是:

let t = Array2D.create 2 2 1.0
t |> Array2D.iter (printfn "%f");;
如果你真的喜欢..的
。。在里面执行
语法:

type Array2DForLoopBuilder() =
    member __.Zero() = ()
    member __.For(a, f) = Array2D.iter f a
    member __.Run e = e

let a2dfor = Array2DForLoopBuilder()

let t = Array2D.init 2 2 (fun a b -> float a + float b)

a2dfor { for x in t do printfn "%f" x }

有趣的是,编译器团队没有针对数组的特殊情况解决这个问题