Why are parentheses needed on read_rest_of_csv
below?
let read_rest_of_csv() =
csv_data.Add(csv_fileH.ReadFields()) |> ignore
not csv_fileH.EndOfData
while read_rest_of_csv() do ignore None
Without the parentheses, the loop will not terminate.
open System
open System.Threading
open System.Collections.Generic
open System.Linq
open System.Text
open System.Threading.Tasks
open System.IO
open Microsoft.VisualBasic.FileIO
[<EntryPoint>]
let main argv =
let csv_fileH = new TextFieldParser("test1.csv")
csv_fileH.TextFieldType = FieldType.Delimited |> ignore
let x = csv_fileH.SetDelimiters(",")
let csv_data = new List<string[]>()
let eod = csv_fileH.EndOfData
if not eod then
let column_headings = csv_fileH.ReadFields()
csv_data.Add(column_headings) |> ignore
let read_rest_of_csv =
csv_data.Add(csv_fileH.ReadFields()) |> ignore
not csv_fileH.EndOfData
while read_rest_of_csv do ignore None
0
I apologize that I cannot remember where I saw this. I think it was in SO. It's a nice example.
Could this be that without parens I'm dealing with a function object of sorts?
I am indeed coming from not only a C, C++, and C# background, but also an intermediate Clojure background as well. In my case with F# syntax, reading my Haskell manual in a little more detail might have helped, because the syntaxes seem similar.
It seems that people coming from C-family languages (C#, Java, C, C++, JavaScript) are having problems understanding the use of brackets in F#. I certainly had, and it took me some years learning how things work.
In a nutshell, the most basic building block in F# is a value. Values can be let
-bound:
let foo = bar
This means that foo
is a value, which happens to be equal to bar
.
Functions are also values:
// 'a -> 'a * 'a
let f = fun x -> x, x
Here, f
is a function that takes some value (x
) and returns a tuple with x
as both the first and the second element.
That's a bit cumbersome to write, so there's a shorthand for that:
// 'a -> 'a * 'a
let f x = x, x
Notice that there are no brackets in these expressions.
Sometimes you need to adjust the precedence of operators. Just like in maths, 1 + 2 * 3
(which is equivalent to 1 + (2 * 3)
) isn't the same as (1 + 2) * 3
. In F#, you also use brackets to override precedence. Thus
// 'a -> string * 'a
let f x = someOtherFunction x, x
isn't the same as
// x:'a -> string
let f x = someOtherFunction (x, x)
(in this case, someOtherFunction
is a function that returns a string
.)
Notice that the brackets don't denote a function call; they're only there to control order of evaluation.
Sometimes, you want to define a function that doesn't take any input. You can't, however, define it like this:
let f = whatever
because that would make it a value that's immediately let
-bound to whatever
. Instead, you can let the function take a value of the built-in type unit
. This type only has a single value, which is written ()
:
let f () = whatever
This means that f
is a function that pattern matches its input against the only known value of unit
.
Whenever you invoke f
with ()
, the expression whatever
is evaluated and returned.
Without the parentheses, the content executes once and never again. read_rest_of_csv
has a type of bool
: You are basically saying while true do ignore None
.
The parentheses indicate that read_rest_of_csv
has type unit -> bool
, so every time you invoke it, it reads a row and moves the cursor. Otherwise, it will only do this once.
The answer to your question is that:
let read_rest_of_csv =
csv_data.Add(csv_fileH.ReadFields()) |> ignore
not csv_fileH.EndOfData
is not a function at all. This is no different from:
> let i = 1;;
val i : int = 1
This declares a binding with an integer value. If you want to declare a binding with a function value which takes no parameters, that looks like this:
> let i () = 1;;
val i : unit -> int
The exact same reasoning applies to read_rest_of_csv
. Without the parenthesis, you are declaring a binding with type bool
. With the parenthesis, you are declaring a binding with type unit->bool
i.e. a binding with a function value where the function takes no inputs and returns a bool value.
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