Type of printfn in F#, static vs dynamic string
f#
Solution
Good question. If you look at the type of `printfn`, which is `Printf.TextWriterFormat<'a> -> 'a`, you'll see that the compiler automatically coerces strings into `TextWriterFormat` objects at compile time, inferring the appropriate type parameter `'a`. If you want to use `printfn` with a dynamic string, you can just perform that conversion yourself:
let s = Printf.TextWriterFormat<unit>("hello")
printfn s
let s' = Printf.TextWriterFormat<int -> unit>("Here's an integer: %i")
printfn s' 10
let s'' = Printf.TextWriterFormat<float -> bool -> unit>("Float: %f; Bool: %b")
printfn s'' 1.0 true
If the string is statically known (as in the above examples), then you can still have the compiler infer the right generic argument to `TextWriterFormat` rather than calling the constructor:
let (s:Printf.TextWriterFormat<_>) = "hello"
let (s':Printf.TextWriterFormat<_>) = "Here's an integer: %i"
let (s'':Printf.TextWriterFormat<_>) = "Float: %f; Bool: %b"
If the string is truly dynamic (e.g. it's read from a file), then you'll need to explicitly use the type parameters and call the constructor as I did in the previous examples.
Problem
I just began toying around with F# in Mono and the following problem arose that I cannot quite understand. Looking up information on `printfn` and `TextWriterFormat` didn't bring enlightenment either, so I thought I'm going to ask here. In FSI I run the following: ``` > "hello";; val it : string = "hello" > printfn "hello";; hello val it : unit = () ``` Just a normal string and printing it. Fine. Now I wanted to declare a variable to contain that same string and print it as well: ``` > let v = "hello" in printfn v ;; let v = "hello" in printfn v ;; ---------------------------^ \...\stdin(22,28): error FS0001: The type 'string' is not compatible with the type 'Printf.TextWriterFormat<'a>' ``` I understood from my reading that `printfn` requires a constant string. I also understand that I can get around this problem with something like `printfn "%s" v`. However, I'd like to understand what's going on with the typing here. Clearly, `"hello"` is of type `string` as well as `v` is. Why is there a type problem then? Is `printfn` something special? As I understand it the compiler already performs type-checking on the arguments of the first string, such that `printfn "%s" 1` fails.. this could of course not work with dynamic strings, but I assumed that to be a mere convenience from the compiler-side for the static case.