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.
