Reputation: 25516
I suspect that I am missing something very obvious here but this doesn't work:
let t = Array2D.create 1 1 1.0
for x in t do printfn "%f" x;;
It fails with
error FS0001: The type 'obj' is not compatible with any of the types float,float32,decimal, arising from the use of a printf-style format string
Interestingly using printf "%A"
or "%O"
prints the expected values which suggests to me that the problem is with the type inference
The corresponding code for a 1D array works fine
let t = Array.create 1 1.0
for x in t do printfn "%f" x;;
For reference this is on version 2.0 (both interactive and compiler) running on the latest mono
Upvotes: 0
Views: 655
Reputation: 7560
As Jack pointed out, this is a problem. One easy solution is:
let t = Array2D.create 2 2 1.0
t |> Array2D.iter (printfn "%f");;
And if you really like the for .. in .. do
syntax:
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 }
Upvotes: 3
Reputation: 11525
In .NET, a 1D array implicitly implements IList, which means it also implements (by inheritance) IEnumerable<T>
. So, when you run:
let t = Array.create 1 1.0
for x in t do printfn "%f" x;;
the F# compiler emits code which gets an implementation of IEnumerable<T>
(seq<T>
in F#) from t
, then iterates over it. Since it's able to get an IEnumerable<T>
from the array, x
will have type T
.
On the other hand, multi-dimensional arrays (2d, 3d, etc.) only implement IEnumerable
(not IEnumerable<T>
) so the F# compiler infers the type of x
as System.Object
(or obj
, in F#).
There are two solutions for what you want:
Cast each individual value within the loop, before printing it:
for x in t do printfn "%f" (x :?> float);;
Or, use Seq.cast to create and iterate over a strongly-typed enumerator:
for x in (Seq.cast<float> t) do printfn "%f" x;;
Upvotes: 7