问题
I need to call a function that takes System.Array []
as one parameter in F#. (The function is in a library).
I need to pass an argument of type float [] [] []
but the compiler refuses to compile. To replicate the problem, I wrote the following code
let x : float [] [] = Array.init 2 (fun x -> Array.zeroCreate 3)
x :> System.Array;; // This is OK
val x : float [] [] = [|[|0.0; 0.0; 0.0|]; [|0.0; 0.0; 0.0|]|]
> x :> System.Array [];; //Error
x :> System.Array [];;
^^^^^^^^^^^^^^^^^^^^
stdin(14,1): warning FS0059: The type 'System.Array []' does not have any proper subtypes and need not be used as the target of a static coercion
x :> System.Array [];;
^^^^^^^^^^^^^^^^^^^^
stdin(14,1): error FS0193: Type constraint mismatch. The type
float [] []
is not compatible with type
System.Array []
The type 'System.Array' does not match the type 'float []'
How can I solve this problem?
Thanks in advance.
回答1:
You could do this:
let x : float [] [] = Array.init 2 (fun x -> Array.zeroCreate 3)
let toArray (xs : #System.Array []) =
Array.map (fun x -> x :> System.Array) xs
let x' : System.Array [] = toArray x
回答2:
The ability to treat an 's[]
as a 't[]
when 's :> 't
makes the .NET type system unsound (and is probably due to the fact that Java does the same thing). Unfortunately, C# follows .NET in allowing this.
Because it's a .NET runtime feature, you can also do it in F# via boxing and unboxing:
let x : float[][] = Array.init 2 (fun x -> Array.zeroCreate 3)
let x' = (box x) :?> System.Array[]
This avoids the overhead of mapping each element as in Ramon's solution.
To see why this makes the .NET type system unsound, consider this:
x'.[0] <- upcast [| "test" |] // System.ArrayTypeMismatchException
Even though we are storing a value of type System.Array
into a System.Array[]
, we get an exception at runtime because the true type of the underlying array can't support the operation (x
and x'
are just two views of the same array, and obviously a string[]
can't be stored into x
). This unsoundness in the .NET type system therefore has the undesirable side effect of requiring additional overhead for most stores into arrays to ensure that the stored value has a type compatible with the underlying array. In my opinion, it's a good thing that F# prevents you from doing this directly.
来源:https://stackoverflow.com/questions/7916212/system-array-not-compatible-with-float-in-f