https://tryfsharp.fsbolero.io/
printfn "Hello"
works as expected without errors, however, using pipe operator
"Hello" |> printfn
The type 'string' is not compatible with the type 'Printf.TextWriterFormat'
I understood the pipe operator behavior:
f(a)
is equivalent to a |> f
Why does the latter generate the error?? Thanks.
CodePudding user response:
Yes. The pipe operator does what you think it does. However, printfn
is "special" that it takes a kind of "formattable string" (there are different kinds of these) and the compiler does its magic only when the format string appears as a direct argument.
In other words, your "Hello"
in the first example is not really a string, it is a Printf.TextWriterFormat
object, magically created by the compiler.
Still, you can do what you want by using an explict format string. This approach you'll see quite a bit in real-world code:
"Hello" |> printfn "%s"
Here, %s
means: give me a string. The magic of F# in this case again takes the format string, here "%s"
, this time with an argument of type string
, and turns it into a function.
Note 1: that this "surprise effect" is being considered and the community works towards adding a printn
function (i.e., without the f
which stands for format
) to just take a simple string: https://github.com/fsharp/fslang-suggestions/issues/1092
Note 2: if you do want to pass arguments to printfn
around, you can make the type explicit, but this is done very rarely:
let x = Printf.TextWriterFormat<unit> "Hello"
x |> printfn // now it's legal
Note 3: you might wonder why the compiler doesn't apply its magic to the lh-side of |>
as well. The reason is that |>
is not an intrinsic to the compiler, but just another overridable operator. Fixing this is therefor technically very hard (there can be any amount of operators on the lh-side), though it has been considered at certain times.