What does this '()' notation mean?

I just started to learn F#. The book uses the following notation:

let name() = 3
name()

what that differs from this:

let name = 3
name

?


Solution 1:

Before answering what () is lets get some basics defined and some examples done.

In F# a let statement has a name, zero or more arguments, and an expression.

To keep this simple we will go with:
If there are no arguments then the let statement is a value.
If there are arguments then the let statement is a function.

For a value, the result of the expression is evaluated only once and bound to the identifier; it is immutable.
For a function, the expression is evaluated each time the function is called.

So this value

let a = System.DateTime.Now;;

will always have the time when it is first evaluated or later invoked, i.e.

a;;
val it : System.DateTime = 1/10/2017 8:16:16 AM ...  
a;;
val it : System.DateTime = 1/10/2017 8:16:16 AM ...  
a;;
val it : System.DateTime = 1/10/2017 8:16:16 AM ...  

and this function

let b () = System.DateTime.Now;;

will always have a new time each time it is evaluated, i.e.

b ();;
val it : System.DateTime = 1/10/2017 8:18:41 AM ...  
b ();;
val it : System.DateTime = 1/10/2017 8:18:49 AM ...  
b ();;
val it : System.DateTime = 1/10/2017 8:20:32 AM ... 

Now to explain what () means. Notice that System.DateTime.Now needs no arguments to work.

How do we create a function when the expression needs no arguments?

Every argument has to have a type, so F# has the unit type for functions that need no arguments and the only value for the unit type is ().

So this is a function with one argument x of type int

let c x = x + 1;;

and this is a function with one argument () of type unit

let b () = System.DateTime.Now;;

Solution 2:

Definitely do NOT think of () as some syntax for a function call or anything like that. It's just a value, like 3, 5, 'q', false, or "blah". It happens to be a value of type Unit, and in fact it's the only value of type unit, but really that's beside the point. () here is just a value. I can't stress that enough.

First consider

let name x = 3

What's this? This just defines a function on x, where x can be any type. In C# that would be:

int Name<T>(T x) 
{
    return 3;
}

Now if we look at let name () = 3 (and I somewhat recommend putting that extra space there, so it makes () look more a value than some syntactic structure) then in C# you can think of it as something like (pseudocode)

int Name<T>(T x) where T == Unit  //since "()" is the only possible value of Unit
{
    return 3;
}

or, more simply

int Name(Unit x)
{
    return 3;
}

So we see that all let name () = 3 is, the definition of a function that takes a Unit argument, and returns 3, just like the C# version above.

However if we look at let name = 3 then that's just a variable definition, just like var name = 3 in C#.

Solution 3:

In

let name() = 3
name()

name is a function, of type unit -> int.

In

let name = 3
name

name is an integer, of type int.

In F#, every function has an input type and an output type. The input type of let name() = 3 is unit, which has only one value (). Its output type is int, which has values from –2,147,483,648 to 2,147,483,647. As another example type bool has only two values, true and false.

So back to you question what's the usage of (). If you don't specify the input value of a function, it cannot get executed. So you have to specify an input value to your function let name()=3 to get it executed and because of its input type is unit, the only value you can use is ().

Here is another way to define the name function:

let name : (unit -> int)  = (fun _ -> 3);;

and compare this to:

let name : int = 3

Solution 4:

Using () creates a function which takes a paramter of type unit, rather than the second case which is just a simple integer.

This is particularly important when you want to control execution of the function.

The main difference is when you have

let name() = 
    printfn "hello"
    1

vs

let name = 
    printfn "hello"
    1

then

let t = name + name

will print "hello" once. But

let t = (name()) + (name())

will print "hello" twice.

You have to be careful with this when considering the order in which functions are evaluated.

Consider the following program:

let intversion = 
    printfn "creating integer constant"
    1

printfn "integer created"

let funcversion() =
    printfn "executing function"
    1

printfn "function created"

let a = intversion + intversion
printfn "integer calculation done"
let b = (funcversion()) + (funcveriosn())
printfn "function calculation done"

This will print the following in order

  1. creating integer constant
  2. integer created
  3. function created
  4. integer calculation done
  5. executing function
  6. executing function
  7. function calculation done