Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# - creating delegates

Currently reading a series of blogposts on F#, targeted at the C# programmer. Right now I've finished reading part 3 ( http://www.jelovic.com/weblog/?p=220 ) and am left puzzled.

The difference between

let readLine = Console.ReadLine ()

and

let readLine () = Console.ReadLine ()

is clear enough but why is there the need to specify the two braces - () - in the following line:

let print (text : string) () = Console.WriteLine text

Shouldn't the compiler be able to figure out you're declaring a delegate print by omitting the braces, so it would look as follows:

let print (text : string) = Console.WriteLine text

Also, the following line made little sense to me

Usually when you have a function that takes parameters of a different type the compiler can differentiate between a function call and a delegate reference, but for unit you have to force it.

Does this mean that when the parameters are different it is safe for the compiler to assume it's a function call?

thank you all for the answers, it's clear to me now. As for the quote, we'll let it rest.

like image 680
Opflash Avatar asked Dec 28 '22 05:12

Opflash


1 Answers

Introduction. I think it's useful to first discuss the difference in the simple example as it helps to understand what "unit" value is. The first declaration creates a string value (and immediately calls ReadLine to obtain the input from the user):

> let readLine = Console.ReadLine ();;
val readLine : string

The second declaration creates a function that takes unit value as an argument. The function doesn't need to take any input, but we want to define it as a function, so that it can be executed repeatedly (we need that, because the function has side-effect - it reads input from the user).

The "unit" parameter is just a way of creating a function that takes something as argument. "Unit" has only a single value written as (), so it doesn't represent any information - just the fact that there is some parameter:

> let readLine () = Console.ReadLine ();;
val readLine : unit -> string

Your question. To look at your example with additional braces. This creates a function that takes a string as the first parameter and takes additional "unit" value as the second parameter. You can see that from the type signature:

> let print (text : string) () = Console.WriteLine text 
val print : string -> unit -> unit

This is valid F# declaration, but it is not very useful. It means that the function will be only called when you give it some string to print and also additional "unit" value. You can call it like this:

print "Hello" ()

Even without the additional "unit" parameter, it would be a function (as opposed to a value), so adding the additional parameter doesn't help (you're always creating a function that can be called to print different strings).

There are still cases where this declaration can be interesting. For example, you can call the function just with the string as a parameter. In this case, you'll get a function as the result. The returned function will take unit and will print the string:

let f = print "Hello" // doesn't print anything
f ()                  // prints "Hello"
f ()                  // prints "Hello" again!

So, the compiler allows you to use "unit" values as any other values in the language. This includes uses that may look a bit unfamiliar (and not very useful) at first, but can make a good sense in some scenario.

like image 57
Tomas Petricek Avatar answered Jan 06 '23 22:01

Tomas Petricek