Home > Software engineering >  "Hello" |> printfn generates an error in F#
"Hello" |> printfn generates an error in F#

Time:08-20

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.

  • Related