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