I found the code below in the book F# Design Patterns
by Gene Belitski. I have been reading about F# but I have not found an explanation for this syntax either on that book or elsewhere. I understand the keyword yield
and what it does and I know that both the yield and printfn statements return values are of type unit. What I do not understand is the square brackets. The statements are not separated by semicolons as they would in a literal list creation. This must be a special syntax but I cannot find references to it. Can someone help?
let eagerList = [
printfn "Evaluating eagerList"
yield "I"
yield "am"
yield "an"
yield "eager"
yield "list" ]
Square brackets are used, usually in books and articles, when supplying words that make a quotation clearer or that comment on it, although they were not originally said or written.
Use square brackets to include words within a quote that are not part of the original quote. For example, if a quoted passage is not entirely clear, words enclosed in square brackets can be added to clarify the meaning.
Square Brackets are placed around extra information in a text; and are typically used for editorial comments, corrections, and clarifications. Square brackets can also be used to add something into a sentence that was taken out by the writer.
Parentheses. Brackets: In a paper, use brackets to signify important information added to direct quotes. The brackets tell the reader that the information is added to further explain the quote.
It is a list.
You can define a list by explicitly listing out the elements, separated by semicolons and enclosed in square brackets.
let eagerList = [ printfn "Evaluating eagerList"; yield "I"; yield "am"; yield "an"; yield "eager"; yield "list" ]
You can also put line breaks between elements, in which case the semicolons are optional. The latter syntax can result in more readable code when the element initialization expressions are longer, or when you want to include a comment for each element.
let eagerList = [
printfn "Evaluating eagerList"
yield "I"
yield "am"
yield "an"
yield "eager"
yield "list" ]
Both of these codes do exactly the same.
Note, that the second snippet could have also been written like this, as the semicolons are optional if you put line breaks between elements.
let eagerList = [
printfn "Evaluating eagerList";
yield "I";
yield "am";
yield "an";
yield "eager";
yield "list"; ]
Check out this.
That is actually a list comprehension or some sort of computation expression. I think that example conflates a few different things which probably baffles you, so maybe that book is actually not the best first or intro book to F#. If you read p. 169 carefully it explains what it is all about though. Author wants to demonstrate that with Seq.delay
, well, you can delay the eager evaluation. If you evaluate the list first it actually prints the "Evaluating eager list" part, but only when you create it. After that it won't. You can see that printfn
is not part of the list. So it's more like a statement, one printfn, and an expression (string list) combined.
Usually you will just generate a list, and not type it in but you can separate the items with a newline or a ;
. So these two lists are equivalent:
["a";"b";"c"]
["a"
"b"
"c"
]
yield
is sort of like return
in C#, it doesn't return unit, it returns a value, especially in a sequence. When you create the example you will get this:
Evaluating eagerList
val eagerList : string list = ["I"; "am"; "an"; "eager"; "list"]
So you can see the printfn
is not part of the list.
If you run eagerList
you will only see:
val it : string list = ["I"; "am"; "an"; "eager"; "list"]
Confirming our suspicion.
Now what Gene Belinitsky wanted to demonstrate is this:
let delayed = Seq.delay (fun _ -> ([
printfn "Evaluating eagerList"
yield "I"
yield "am"
yield "an"
yield "eager"
yield "list" ] |> Seq.ofList))
val delayed : seq
Not only it doesn't print out the list, it doesn't event prints the printfn statement! And it's a seq, not a list.
If you do delayed
or delayed |> Seq.toList
each time you will get back the result from the printfn statement as well as the string list:
Evaluating eagerList
val it : string list = ["I"; "am"; "an"; "eager"; "list"]
So to summarize it, yes, usually within [] you have a list and you either separate the itenms with a ;
or a newline. However that specific example is not actually a usual list but an expression designed to demonstrate how you can delay evaluation, and for that it contains a print statement as well as a string list.
Also ;
can be used to separate statements on the same line, e.g.
printfn "%A" "foo";printfn "%A" "bar"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With