Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What do square brackets without semicolons mean?

Tags:

f#

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" ]
like image 486
Soldalma Avatar asked Feb 11 '17 12:02

Soldalma


People also ask

What does [] mean in writing?

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.

What do square brackets mean in writing?

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.

When should square brackets be used?

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.

What does bracketed text mean?

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.


2 Answers

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.

like image 161
hm1912 Avatar answered Oct 08 '22 23:10

hm1912


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.

  1. List syntax

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"
]
  1. Lists are always eager in F#, however seqs are lazy.
  2. 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"

like image 41
s952163 Avatar answered Oct 08 '22 22:10

s952163