问题
I have the following method:
member this.addColumnWithHeading heading column =
this.addColumn (seq { yield heading; yield! (column |> Seq.map string)})
which takes a string heading and any sequence (which is compiled to seq in this case), creates a sequence of strings and calls another method with this data. However, it doesn't work with column being a sequence of floats:
Error 1 The type 'obj' does not match the type 'float' C:\Users\ga1009\Documents\PhD\cpp\pmi\fsharp\pmi\Program.fs 138
How can I define the method addColumnWithHeading
so that it works with floats as well?
回答1:
The built-in string
function is an inline function which uses a statically-resolved generic parameter; since your addColumnWithHeading
method is not declared inline
, the F# type inference has to assume the values in the sequence are of type obj
.
There's a simple solution though -- swap out the string
function in favor of "manually" calling .ToString()
on the values in the sequence. If you do that, F# will be able to use a standard generic parameter type for the sequence so you can pass a sequence of any type you desire.
member this.addColumnWithHeading heading column =
seq {
yield heading
yield! Seq.map (fun x -> x.ToString()) column }
|> this.addColumn
回答2:
string
is inlined so its argument type has to be resolved at compile-time. Since your member is not inlined it picks the most general type it can (obj
in this case). Inlining your method will allow column
to remain generic.
member inline x.AddColumnWithHeading(heading, column) =
x.AddColumn(seq { yield heading; yield! Seq.map string column })
EDIT
Per the comments to Jack's answer, you might not need to inline your use of string
. Certainly, if column
will always be seq<float>
you should just add a type annotation. Passing seq<string>
and moving the string conversion outside the function is another option.
来源:https://stackoverflow.com/questions/12162057/seqobj-versus-seqfloat-in-f