Reputation: 2653
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
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
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