let 5 = 6
Here’s a small GHCi session:
Prelude> let 3 - 4 = 5 Prelude> 3 - 4 5 Prelude>
Wait, what? Oh, right, I guess this isn’t very special: we’re just redefining the minus operator, and for some very specific input at that.
Prelude> 1 - 2 *** Exception:
: Non-exhaustive patterns in function - Prelude>
Yes, that’s what we were expecting. How about the following?
Prelude> let 5 = 6 Prelude>
Wait, what? GHC seems to accept our definition of 5. Have we really redefined 5?
Prelude> 5 5 Prelude>
No, it seems it’s just ignored it. What does
let 5 = 6 mean, then?
To find out, remember that anywhere you define values using
=, you may write patterns on the left-hand side, unwrapping constructors and directly naming fields inside. Here’s an example:
Prelude Data.List> let Just ix = elemIndex 'j' ['a'..'z'] Prelude Data.List> ix 9 Prelude Data.List>
This works even in a top-level declaration in your module! There’s no limit to the number of values you may introduce:
Prelude> let one : two : three : _ = [1..] Prelude> (two, three) (2,3) Prelude>
So if we can introduce any number of values, can we also introduce zero new names?
Prelude> let Just True = Nothing Prelude> let _ = "meep" Prelude>
lets are accepted. They just don’t do anything useful.
Now we can figure out what
let 5 = 6 means: the pattern on the left-hand side of
= contains no new names and so no new names are bound, just like in the example above. This opposed to our very first example, where there is a new name on the left-hand side, namely
On a final note, here is what happens when the patterns don’t match the values on the right-hand side:
Prelude> let ('a', b) = ('b', 'c') Prelude> b *** Exception:
: Irrefutable pattern failed for pattern ('a', b)
Two more cases to consider (with subtly different semantics):
let !5 = 6
5 <- return 6
[...] let 5 = 6 By gracjanpolak Tłumaczone z let 5 = 6 by Martijn van Steenbergen: [...]
I find your post to be the best introduction to pattern matching ever! Just translated to Polish word for word on my blog here: http://gracjanpolak.wordpress.com/2009/10/02/let-5-6/. I hope you don’t mind (link back is inside).
@lilac Thanks! Those are pretty neat.
@gracjan Thanks! I’m glad you like it. And no, I don’t mind at all. Thanks for linking back.
@lilac There’s also more to be said about !’s dual, the ~.
How come “let 5 = 6″ doesn’t throw a “Irrefutable pattern” exception?
@Matt R: Because Haskell is lazy! See this Reddit comment for a nice discussion.
For me, this became much clearer when translated into lambda-notation (as I said on this other Reddit comment): It’s much clearer to me what’s happening when I change
let 5 = 6 in f 5to
(5 -> f 5) 6—there’s a non-exhaustive pattern match crying out for attention! (Have I translated it incorrectly?)
Now, if I do
let Just a = Nothing
why does GHCI tell me that “a” is of type GHC.Prim.Any?
Leave a comment!
Martijn loves to receive comments! Add yours by filling out the fields below.