问题
Can anyone please explain why this results in an error:
let xs = [| "Mary"; "Mungo"; "Midge" |]
Array.iter printfn xs
Whilst this does not:
Array.iter printfn [| "Mary"; "Mungo"; "Midge" |]
回答1:
The signature of printfn is Printf.TextWriterFormat<'a> -> 'a
. The compiler infers literal values of strings as Printf.TextWriterFormat<unit>
but cannot do so with dynamic strings.
You can help the compiler in the first example by adding correct type annotation:
let xs: Printf.TextWriterFormat<unit> [] = [| "Mary"; "Mungo"; "Midge" |]
Array.iter printfn xs
or using explicit constructors:
let xs = [| "Mary"; "Mungo"; "Midge" |]
Array.iter (fun s -> printfn <| Printf.TextWriterFormat<unit>(s)) xs
In general, it's too verbose to do so. Therefore, specifying format strings such as "%s"
for strings and "%O"
for types overriding ToString()
method is the good way to go:
let xs = [| "Mary"; "Mungo"; "Midge" |]
Array.iter (printfn "%s") xs
回答2:
In addition to @pad's excellent answer.
The main reason for confusion is misunderstanding of what happens with the arguments. Let's look at single iteration. It supposed to be
printfn "%s" "Mary" // or whatever default format specifier instead of %s
but in fact, it is
printfn "Mary" ()
So "Mary"
is not a string to be formatted. It is a format specifier, quite useless but well suitable for formatting a unit
.
Try this modification to your sample:
Array.iter printfn [| "Mary %s"; "Mungo"; "Midge" |]
and it will refuse to compile.
来源:https://stackoverflow.com/questions/11708229/f-printfn-anomaly