By running printfn "%A" "c", I get "c".
By running printfn "%s" "c", I get c.
Why the difference? The same goes for char.
The %A specifier tries to hint at object types - the "c" is it trying to show it is a string. When you do %s the compiler knows you want to print a string so it doesn't print the quotes
Because printfn "%A" uses reflection, it displays results the same as values automatically printed out by F# Interactive. On the other hand, %s is for strings only, and it shows contents of strings.
The generic case of "%s" is "%O" when ToString methods are used. The %A specifier is slow, but helpful for structural types and types without overridden ToString methods.
Related
I am learning F# but I just don't understand how I am supposed to use ToString. Below are a few attempts. The syntax errors are saying it is expecting type string but that it is actually type uint -> string. So it doens't actually appear to be invoking a function? Could this be explained? This seems like such a simple thing to do but I can't figure it out.
open System
open System.IO
open FSharp.Data
[<EntryPoint>]
let main (args: string[]) =
let htmlPage = HtmlDocument.Load("https://scrapethissite.com/")
printfn "%s" htmlPage.ToString // This causes a syntax error
htmlPage.ToString
|> (fun x -> printfn "%s" x) // This also causes a syntax error
0
.ToString is a method, not a value. In F# every method and every function has a parameter. In fact, that's how functions differ from values (and methods from properties): by having a parameter.
Unlike in C#, F# methods and functions cannot be parameterless. If there is nothing meaningful that you'd want to pass to the method, that method would still have one parameter of type unit. See how this is visible in the error message? unit -> string is the type.
To call such method, you have to pass it the parameter. The sole value of type unit is denoted (). So to call the method you should do:
htmlPage.ToString ()
|> printfn "%s"
Your first example is a bit more complicated. The following would not work:
printfn "%s" htmlPage.ToString ()
Why? Because according to F# syntax this looks like calling printfn and passing it three parameters: first "%s", then htmlPage.ToString, and finally (). To get the correct order of calls you have to use parentheses:
printfn "%s" (htmlPage.ToString ())
And finally, general piece of advice: when possible try to avoid methods and classes in F# code. Most things can be done with functions. In this particular case, the ToString methods can be replaced with the equivalent function string:
printfn "%s" (string htmlPage)
I have a function that takes a string and sends it to a terminal:
Print: string -> unit
it is passed to several modules that do this, to simplify the syntax
// printing
let print = settings.Print
and then it's used like that:
print "hello"
print (sprintf "the time is %A" DateTime.UtcNow)
my question is: Can I make two functions, with the same name but two signatures, so I could use it to either print a string, or a sprintf, then print the string.
for example:
print "hello"
print "the time is %A" DateTime.UtcNow
Is this possible? the goal is to simplify the syntax as a lot of code is peppered with info being sent to the terminal (which is currently a Telegram channel)
You can use kprintf for this:
let myPrint s = printfn "My print: %s !" s
let print x = Printf.kprintf myPrint x
print "%d" 1
print "aaaa"
print "%s %s" "b" "c"
There are some examples here and here.
I couldn't find kprintf documentation, so I'm not sure that this usage is correct, but it produces the correct result for me. Another possible candidate is ksprintf, which also produces the same result.
You can use the same signature as sprintf:
let print (format : Printf.StringFormat<'T>) =
sprintf format
|> dosomethingElse
and you can use it as you want:
print "hello"
print "the time is %A" DateTime.UtcNow
I have following printing example in F#
for row in data.Rows do
printfn "Example: (%s)" row.A
But I received this error
Script1.fsx(15,67): error FS0001: This expression was expected to have
type
string but here has type
Guid
I didn't find any example of printing of Guid type.
I tried apply ToString() method to row.A but it is not working as well
There are two options here:
for row in data.Rows do
printfn "Example: (%s)" (row.A.ToString())
or
for row in data.Rows do
printfn "Example: (%A)" row.A
Here the %A can be used for any type and the compiler will automatically print it for you
You can use %A for a Guid, like this:
printfn "Example: (%A)" row.A
When using %s, the type must be a string.
The MSDN Documentation has more information about which format type to use and how it behaves.
In addition to the answers already given, it's worth noting that Guid also supports an overload of ToString, giving you the option to control how the GUID string is formatted.
You could, for example, write it out like this:
printfn "Example: (%s)" (row.A.ToString "n")
if you want to omit the hyphens (Example: (78e6fb89dc5045988d445c4d8aef4e28)).
Or you could use stringf for this, if you want an alternative with pipes instead of parentheses:
row.A |> stringf "n" |> printfn "Example: (%s)"
or if you don't need the formatting option:
row.A |> string |> printfn "Example: (%s)"
How do I print out a number with a unit? Shall I use "%A" or shall I strip the unit first? MSDN doesn't say anything: http://msdn.microsoft.com/en-us/library/vstudio/ee370560.aspx
[<Measure>] type hr
let a = 10<hr>
printf "%d" a // <-- doesn't compile: Unit of measure 'hr' doesn't match the unit of measure '1'
If you would like strong typing for your hr unit of measure you could use "%a".
printf "%a" expects a function where the first parameter is a TextWriter and the second is any value you specify. Using this would allow you to require int<hr> as the second argument which will provide type checking at compile time.
Have a look at the code below:
open System.IO
[<Measure>] type hr
let printHours (tw:TextWriter) (hours:int<hr>) =
tw.Write("{0} hour(s)", hours)
The example in your question would be written as:
let a = 10<hr>
printf "%a" printHours a
This will print 10 hour(s) to the console.
If you pass in a value that does not have an hr unit, you will get a lovely error:
printf "%a" printHours 10;;
printf "%a" printHours 10;;
-----------------------^^
error FS0001: This expression was expected to have type
int<hr>
but here has type
int
I would probably do either printf "%O hour(s)" a or else int a |> printf "%i hour(s)". One is type-safe, and one is short.
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.
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.
This is only somewhat related to your question, but I think it's a handy trick. In C#, I often have template strings for use with String.Format stored as constants, as it makes for cleaner code:
String.Format(SomeConstant, arg1, arg2, arg3)
Instead of...
String.Format("Some {0} really long {1} and distracting template that uglifies my code {2}...", arg1, arg2, arg3)
But since the printf family of methods insist on literal strings instead of values, I initially thought that I couldn't use this approach in F# if I wanted to use printf. But then I realized that F# has something better - partial function application.
let formatFunction = sprintf "Some %s really long %i template %i"
That just created a function that takes a string and two integers as input, and returns a string. That is to say, string -> int -> int -> string. It's even better than a constant String.Format template, because it's a strongly-typed method that lets me re-use the template without including it inline.
let foo = formatFunction "test" 3 5
The more I use F#, the more uses I discover for partial function application. Great stuff.
I don't think that it is correct to say that the literal value "hello" is of type String when used in the context of printfn "hello". In this context the compiler infers the type of the literal value as Printf.TextWriterFormat<unit>.
At first it seemed strange to me that a literal string value would have a different inferred type depending on the context of where it was used, but of course we are used to this when dealing with numeric literals, which may represent integers, decimals, floats, etc., depending on where they appear.
If you want to declare the variable in advance of using it via printfn, you can declare it with an explicit type...
let v = "hello" : Printf.TextWriterFormat<unit> in printfn v
...or you can use the constructor for Printf.TextWriterFormat to convert a normal String value to the necessary type...
let s = "foo" ;;
let v = new Printf.TextWriterFormat<unit>(s) in printfn v ;;
As you correctly observe, the printfn function takes a "Printf.TextWriterFormat<'a>" not a string. The compiler knows how to convert between a constant string and a "Printf.TextWriterFormat<'a>", but not between a dynamic string and a "Printf.TextWriterFormat<'a>".
This begs the question why can't it convert between a dynamic string and a "Printf.TextWriterFormat<'a>". This is because the compiler must look at the contents of the string to and determine what control characters are in it ( i.e. %s %i etc), from this is it works out the type of the type parameter of "Printf.TextWriterFormat<'a>" (i.e. the 'a bit). This is a function that is returned by the printfn function and means that the other parameters accepted by printfn are now strongly typed.
To make this a little clear in your example "printfn "%s"" the "%s" is converted into a "Printf.TextWriterFormat unit>", meaning the type of "printfn "%s"" is string -> unit.