d8d0d65b3f7cf42
d8d0d65b3f7cf42

Reputation: 2653

guards in pattern match in let binding

I am surprised by the semantics of this (third expression below). Start here:

Prelude> let (a,b) = (0,0) in (a,b)
(0,0)

That's fine. Now add a guard, and it's still fine:

Prelude> let (a,b) | True = (0,0) in (a,b)
(0,0)

Now change the guard, and be surprised:

Prelude> let (a,b) | a == b = (0,0) in (a,b)
(^CInterrupted.

How come? - This works:

Prelude> case (0,0) of (a,b) | a == b -> (a,b)
(0,0)

Upvotes: 3

Views: 943

Answers (2)

chi
chi

Reputation: 116139

The let is equivalent to

let (a,b) = if a==b 
            then (0,0) 
            else error "non exhaustive..."

which shows its recursive nature more clearly.

Your misunderstanding comes from your let-to-case translation, which is not correct in the presence of guards (or recursion). To see why, think about how one would translate the following:

let (a,b) | condition1 = (0,0)
          | condition2 = (1,1)

The above can't be rewritten as something like case (0,0) of (a,b) -> ... or case (1,1) of (a,b) -> ..., since you need to evaluate the conditions before choosing between (0,0) and (1,1).

Upvotes: 6

András Kovács
András Kovács

Reputation: 30103

Guards in let-s mean "if the condition evaluates to True, bind lhs to rhs". Since Haskell let-s are recursive, let (a,b) | a == b = (0,0) in (a,b) first tries to evaluate a == b with a and b pointing back to the variables just being defined, which can be evaluated by checking again a == b in the guard, and this results in a loop. It's a loop for the same reason let x = x in x results in a loop when trying to force x.

Upvotes: 8

Related Questions