|

let 5 = 6

Posted on Friday, 02 October 2009 at 10:31.

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> 

Yup, those 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)

Comments

By lilac on Friday, 02 October 2009 at 11:35:

Two more cases to consider (with subtly different semantics):

let !5 = 6
5 <- return 6

By Linktipps #14 :: Blackflash on Friday, 02 October 2009 at 12:42:

[...] [...]

By let 5 = 6 « Haskell. Po polsku. on Friday, 02 October 2009 at 13:45:

[...] let 5 = 6 By gracjanpolak TĹ‚umaczone z let 5 = 6 by Martijn van Steenbergen: [...]

By gracjan on Friday, 02 October 2009 at 13:48:

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).

By Martijn on Friday, 02 October 2009 at 14:24:

@lilac Thanks! Those are pretty neat.

By Martijn on Friday, 02 October 2009 at 14:25:

@gracjan Thanks! I’m glad you like it. :-) And no, I don’t mind at all. Thanks for linking back.

By Martijn on Friday, 02 October 2009 at 14:39:

@lilac There’s also more to be said about !’s dual, the ~.

By Matt R on Friday, 02 October 2009 at 16:47:

How come “let 5 = 6″ doesn’t throw a “Irrefutable pattern” exception?

By JadeNB on Saturday, 03 October 2009 at 04:43:

@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 5 to (5 -> f 5) 6—there’s a non-exhaustive pattern match crying out for attention! (Have I translated it incorrectly?)

By Georg on Sunday, 04 October 2009 at 14:15:

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.