When you say
let 5 = 10
it's not a redefinition of 5, it's a pattern matching, the same which occurs when you say
foo 5 = undefined
... foo 10 ...
The pattern simply fails if it's ever matched.
In let-expressions the match is lazy. This means the match is only being done when a variable bound by it is evaluated. This allows us to write things like
let foo = undefined in 10
In your expression, no variable is bound, so the pattern is never matched.
Arguably such patterns with no variables make no sense in let-bindings and should be detected by the compiler, but the language doesn't forbid them.
Basically,
let 5 = 10 in ...
is equivalent to
case 10 of ~5 -> ...
Note the ~
, which marks a lazy, or irrefutable pattern. This is a pattern that matches everything, and that postpones the match to the point where some variable is actually demanded. There are no variables in the pattern 5
, so nothing ever happens.
This corner case is quite useless, and arguably the compiler should emit a warning here.
To clarify the meaning of lazy patterns, consider this:
case f 3 of
(x,y) -> g 10 x y
here f 3
is evaluated first (to WHNF), exposing the pair constructor. Then x,y
are bound to the (not yet evaluated) pair components. Finally, g 10
is computed, the result is applied to x
(which might be demanded now), and then to y
(which may cause x
or y
to be demanded).
By comparison,
case f 3 of
~(x,y) -> g 10 x y
does not start with evaluating f 3
. Instead x
is bound to the unevaluated fst (f 3)
and y
is bound to the unevaluated snd (f 3)
. We instead start with evaluating g 10
. Then, we apply that to x
: this might cause x
to be demanded, triggering the evaluation of f 3
. Then, we apply the result to y
, causing a similar evaluation. Most implementation will actually share the result of f 3
between x
and y
so that it is computed at most once.
As @n.m. is saying, you are pattern matching. Here are some examples.
Pattern matches can succeed
Prelude> let (a, 10) = (15, 10) in a
15
or fail.
Prelude> let (a, 10) = (15, 15) in a
*** Exception: <interactive>:5:5-22: Irrefutable pattern failed for pattern (a, 10)
Since Haskell is lazy, your code will succeed if you do not use the resulting value. This is essentially what you're doing:
Prelude> let (a, 10) = (15, 15) in "Something else"
"Something else"
Note that the types must still check:
Prelude> let (a, 10, 999) = (15, 15) in "Something else"
<interactive>:7:20: error:
• Couldn't match expected type ‘(t, Integer, Integer)’
with actual type ‘(Integer, Integer)’
• In the expression: (15, 15)
In a pattern binding: (a, 10, 999) = (15, 15)
In the expression: let (a, 10, 999) = (15, 15) in "Something else"
• Relevant bindings include a :: t (bound at <interactive>:7:6)
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