Why are parentheses needed on this F# function?

[亡魂溺海] 提交于 2019-11-30 20:08:06

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!