let () = Random.self_init();;
let _ = Random.self_init ();;
│- : unit = ()
It seems "let ()" returns nothing ?
Sincerely!
let is block-scoped. var is function scoped. let does not allow to redeclare variables. var allows to redeclare variables.
I understood the difference between let and let! with a very simple example. Let me read the doc sentence first, then show the output hands on. ... let is lazy-evaluated: it is not evaluated until the first time the method it defines is invoked.
let can be updated but not re-declared. This is because both instances are treated as different variables since they have different scopes. This fact makes let a better choice than var . When using let , you don't have to bother if you have used a name for a variable before as a variable exists only within its scope.
let is the keyword used to define new variables, like in the following construct:
let pattern = expr
For instance
let a = 2
assigns the value 2 to the name a. (Note this is not a way to assign a value to an already existing variable, but this is another topic).
But the pattern to the left of the = sign can be more than just a name. For instance
let (a,b) = (42,"foo")
defines both a and b, to be respectively 42 and "foo".
Of course, the types on both sides must match.
Which is the case here: both sides are of type int * string.
The expressions to the right of the = sign can also be elaborated, for instance
let foo =
let temp = String.make 10 'a' in
temp.[2] <- 'b';
temp
defines foo as the string "aabaaaaaaa". (As a side note, it also ensures that temp is local to this code snippet).
Now, let's use both: on the left, a pattern matching values of type unit, and on the right, an expression of type unit:
let () = Printf.printf "Hello world!\n"
Which explains the let () = construct.
Now, about the let _, one simply needs to know that _ can be used in a pattern as a wildcard: it matches values of any type and does not bind any name. For instance
let (a,_) = (42,"foo")
defines a as 42, and discards the value "foo". _ means "I know there is something here and I explicitly say I will not use it, so I don't name it". Here _ was used to match values of type string, but it can match value of any type, like int * string:
let _ = (42,"foo")
which does not define any variable and is not very useful. Such constructs are useful when the right hand side has side effects, like this:
let _ = Printf.printf "Hello world!\n"
which explains the second part of the question.
Practical purposes
Both are used and it's rather a matter of taste whether to use one or the other.
let () = is slightly safer as it has the compiler check that the right hand side is of type unit.
A value of any other type than unit is often a bug.
let _ = is slightly shorter (I've seen this argument). (Note that with an editor that automatically closes parenthesizes, the number of keystrokes is the same ;-)
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