Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does let 5 = 10 do? Is it not an assignment operation?

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)