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

走远了吗. 提交于 2019-11-27 19:59:57

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.

Teodor

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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!