I cannot seem to figure out how I can embed strings inside an interpolated string in F#. Superficially, it is very similar to C#. For example, in C# I would write something like
Console.WriteLine($"Truly, it is {(string.IsNullOrEmpty("") ? "" : "not ")}empty.");
//Result: Truly, it is empty. OR Truly, it is not empty.
The parentheses inside the curly brackets allow me to embed additional string literals within the interpolation expression.
I have attempted to replicate this in F# with
printfn $"Truly it is {(match (String.IsNullOrEmpty "l") with | true -> "" | false -> "not ")}empty."
The parentheses wrapping the interpolated expression do not accomplish the same thing, it seems. It suggests using an explicit let binding for the interpolated match expression, but for learning purposes I want to do it in a single line.
Is there a way to do this in F#, or am I stuck defining a let for the embedded ternary?
Use triple-quoted strings:
printfn $"""Truly it is {match (String.IsNullOrEmpty "l") with | true -> "" | false -> "not "}empty."""
Related
In Visual Studio 2015:
let myFunction (``string`` : string) =
"\"Quoted string\"" |> (Regex "\"[^\"]*\"").Match |> string
let myOtherFunction (str : string) =
"\"Quoted string\"" |> (Regex "\"[^\"]*\"").Match |> string
First function generates a compiler error, the string function is underlined in red. ("This expression was expected to have type Match -> 'a but here has type string")
Second function is fine, no problems.
Is this by design?
The reason is, your parameter and the call at the end are the same thing. Double backticks are used to escape the name, they are not part of the name.
So in your case that means that ``string`` and string are exactly the same thing, you are trying to pipe into your string parameter. And yes, this is totally by design.
The C# equivalent are #-escaped names, where for example #hello and hello would clash.
It turns out that it is really hard to google the word comment.
Is is possible to represent "comment" expressions in quotations abstract syntax tree?
<# //this gets ignored by the compiler and don't inject the quotation
#>
If not, can you suggest a workaround to represent the comments?
As Ganesh points out, the Expr type has no way of representing comments - the F# quotations really represent just the AST of the expression, rather than full information about the source code (although you can get a file name & a location of a quoted expression).
To somehow embed comments in quotations, you'd need to come up with a way of embedding comments as valid F# code that means something - so you could e.g. define a dummy function comment and do something like this:
let comment (s:string) = ()
let sample =
<# comment "this is not ignored"
1 + ( comment "this is also not ignored"
4 ) #>
Then you could write an active pattern that looks for an expression of the form comment "..."; <expr> and extract the string and the following <expr>:
open Microsoft.FSharp.Quotations
let (|Comment|_|) = function
| Patterns.Sequential(DerivedPatterns.SpecificCall <## comment ##> (None, [], [Patterns.Value(comment, _)]), body) ->
Some(unbox<string> comment, body)
| _ -> None
Using the pattern, we can now write an (incomplete) pattern matching that succeeds when the top-level expression is some commented body expression:
match sample with
| Comment(comment, body) ->
printfn "// %s\n%A" comment body
This is not a very nice way of doing it, but I guess it is as good as it can get if you want to embed some annotations in a hand-written quotation code.
The Expr type that quotations return doesn't contain any way to represent a comment, so this is very unlikely to be possible.
How can I write a no-op statement in F#?
Specifically, how can I improve the second clause of the following match statement:
match list with
| [] -> printfn "Empty!"
| _ -> ignore 0
Use unit for empty side effect:
match list with
| [] -> printfn "Empty!"
| _ -> ()
The answer from Stringer is, of course, correct. I thought it may be useful to clarify how this works, because "()" insn't really an empty statement or empty side effect...
In F#, every valid piece of code is an expression. Constructs like let and match consist of some keywords, patterns and several sub-expressions. The F# grammar for let and match looks like this:
<expr> ::= let <pattern> = <expr>
<expr>
::= match <expr> with
| <pat> -> <expr>
This means that the body of let or the body of clause of match must be some expression. It can be some function call such as ignore 0 or it can be some value - in your case it must be some expression of type unit, because printfn ".." is also of type unit.
The unit type is a type that has only one value, which is written as () (and it also means empty tuple with no elements). This is, indeed, somewhat similar to void in C# with the exception that void doesn't have any values.
BTW: The following code may look like a sequence of statements, but it is also an expression:
printf "Hello "
printf "world"
The F# compiler implicitly adds ; between the two lines and ; is a sequencing operator, which has the following structure: <expr>; <expr>. It requires that the first expression returns unit and returns the result of the second expression.
This is a bit surprising when you're coming from C# background, but it makes the langauge surprisingly elegant and consise. It doesn't limit you in any way - you can for example write:
if (a < 10 && (printfn "demo"; true)) then // ...
(This example isn't really useful - just a demonstration of the flexibility)
When quoting
<# 1 + 1 #>
I want "1 + 1"
instead of
"Call (None, Int32 op_Addition[Int32,Int32,Int32](Int32, Int32),
[Value (1), Value (1)])"
You'll have to write it yourself. See the F# quotations visualizer code as a guide for transforming the quotations abstract syntax tree.
I have implemented a quotation decompiler as part of a larger open source project Unquote. It can decompile many simple F# quoted expressions as single-line non-light syntax strings (see the project's home page for a list of decompiler features). For example,
> decompile <# (11 + 3) / 2 = String.length ("hello world".Substring(4, 5)) #>;;
val it : string =
"(11 + 3) / 2 = String.length ("hello world".Substring(4, 5))"
#Kurt Schelfthout is correct about the many challenges faced when decompiling F# Quotations into human readable form. But from my work so far, I believe that it is possible to write a quotation decompiler which can generate correct F# code. Take match expressions and computation expressions for example, the Unquote decompiler can produce correct F# code in the following simple cases:
> decompile <# match true with | true -> "hi" | _ -> "bye" #>;;
val it : string =
"let matchValue = true in if matchValue then "hi" else "bye""
> decompile <# seq {yield 1; yield 2} #>;;
val it : string =
"seq (Seq.delay (fun unitVar -> Seq.append (Seq.singleton 1) (Seq.delay (fun unitVar -> Seq.singleton 2))))"
Infix and prefix operators are not too hard (as you can see in the first example), but source structure such as new lines and indentation is an interesting topic (though not terribly difficult, I think). However, single-line non-light syntax is sufficient for Unquote's requirements.
There is none, and it's not quite that easy, except in very simple cases. One of the main problems, for example, is the match construct. It is syntactic sugar for a whole bunch of if and switch statements (try printing a quotation with a match in, you'll see). Another one of those biggies are computation expressions, but I guess you could skip those at first.
Then there is a the rabbit hole of ambiguities you'll have to resolve, with conventions like the pipe operator starts a new line, let starts a new line, indentation, infix, prefix, special cases like the (::) operator and so forth.
All in all, doable, but not trivial. Sort of like decompiling.
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.