Pattern guards and where clauses

While playing with some pattern guard code, I discovered some scoping behavior that I wasn't expecting. I learned that pattern guard bindings aren't visible in their equation's where clauses. To make this concrete, in the following (contrived) example, "test1" works, but "test2" complains that 'v' is unbound: data Bar = Baz Int | Biz Int | Empty toInt (Baz i) = Just i toInt (Biz i) = Just (2 * i) toInt Empty = Nothing test1 :: Bar -> Int test1 b | Just v <- toInt b = v + 1 test1 _ = 0 test2 :: Bar -> Int test2 b | Just v <- toInt b = k where k = v + 1 test2 _ = 0 From an implementation perspective, I understand the behavior as an artifact of desugaring pattern guards into a case expression. But, as a user, it seems like an odd restriction on how I organize my code (since I often prefer to separate out tricky bits of logic into nearby where clauses without disturbing the main flow of the right-hand side). Moreover, unless I'm missing something, a slight tweak to the desugaring (by adding irrefutable patterns corresponding to the pattern guard bindings) could easily recover the behavior I expected. I'm thinking something like this (which could be tweaked to remove the repeated expression, of course): test2' :: Bar -> Int test2' b | Just v <- toInt b = k where Just v = toInt b k = v + 1 Anyway, what do other people think? Do people besides me find it pleasing to have pattern guard bindings visible in where clauses? Or are people more worried about the failures that would happen if you used a binding from a pattern guard that ended up false? - Ravi

On 11/20/06, Ravi Nanavati
While playing with some pattern guard code, I discovered some scoping behavior that I wasn't expecting. I learned that pattern guard bindings aren't visible in their equation's where clauses. To make this concrete, in the following (contrived) example, "test1" works, but "test2" complains that 'v' is unbound:
data Bar = Baz Int | Biz Int | Empty
toInt (Baz i) = Just i toInt (Biz i) = Just (2 * i) toInt Empty = Nothing
test1 :: Bar -> Int test1 b | Just v <- toInt b = v + 1 test1 _ = 0
test2 :: Bar -> Int test2 b | Just v <- toInt b = k where k = v + 1 test2 _ = 0
From an implementation perspective, I understand the behavior as an artifact of desugaring pattern guards into a case expression. But, as a user, it seems like an odd restriction on how I organize my code (since I often prefer to separate out tricky bits of logic into nearby where clauses without disturbing the main flow of the right-hand side).
Moreover, unless I'm missing something, a slight tweak to the desugaring (by adding irrefutable patterns corresponding to the pattern guard bindings) could easily recover the behavior I expected.
I'm thinking something like this (which could be tweaked to remove the repeated expression, of course):
test2' :: Bar -> Int test2' b | Just v <- toInt b = k where Just v = toInt b k = v + 1
Anyway, what do other people think? Do people besides me find it pleasing to have pattern guard bindings visible in where clauses? Or are people more worried about the failures that would happen if you used a binding from a pattern guard that ended up false?
What about this case:
test2 :: Bar -> Int test2 b | Just v <- toInt b = k | v <- () = k | otherwise = k where k = v + 1 test2 _ = 0
Making bindings available outside their scope is just plain wrong (and obviously so), imo. Perhaps you're looking for a let-expression instead of a where-clause? -- Cheers, Lemmih

| From an implementation perspective, I understand the behavior as an | artifact of desugaring pattern guards into a case expression. But, as a It's definitely not an artefact of the implementation; it's just a consequence of Haskell's design. 'where' clauses scope over multiple guards, and must do so f x | wibble > 0 = rhs1 | wibble < 0 = rhs2 | otherwise = rhs3 where wibble = sqrt x + 77 Remember you can use 'let' in pattern guards test2 :: Bar -> Int test2 b | Just v <- toInt b, let k = v+1 = k Simon | -----Original Message----- | From: haskell-prime-bounces@haskell.org [mailto:haskell-prime-bounces@haskell.org] On Behalf Of | Ravi Nanavati | Sent: 20 November 2006 01:47 | To: haskell-prime@haskell.org | Subject: Pattern guards and where clauses | | While playing with some pattern guard code, I discovered some scoping | behavior that I wasn't expecting. I learned that pattern guard bindings | aren't visible in their equation's where clauses. To make this concrete, | in the following (contrived) example, "test1" works, but "test2" | complains that 'v' is unbound: | | data Bar = Baz Int | Biz Int | Empty | | toInt (Baz i) = Just i | toInt (Biz i) = Just (2 * i) | toInt Empty = Nothing | | test1 :: Bar -> Int | test1 b | Just v <- toInt b = v + 1 | test1 _ = 0 | | test2 :: Bar -> Int | test2 b | Just v <- toInt b = k | where k = v + 1 | test2 _ = 0 | | From an implementation perspective, I understand the behavior as an | artifact of desugaring pattern guards into a case expression. But, as a | user, it seems like an odd restriction on how I organize my code (since | I often prefer to separate out tricky bits of logic into nearby where | clauses without disturbing the main flow of the right-hand side). | | Moreover, unless I'm missing something, a slight tweak to the desugaring | (by adding irrefutable patterns corresponding to the pattern guard | bindings) could easily recover the behavior I expected. | | I'm thinking something like this (which could be tweaked to remove the | repeated expression, of course): | | test2' :: Bar -> Int | test2' b | Just v <- toInt b = k | where Just v = toInt b | k = v + 1 | | Anyway, what do other people think? Do people besides me find it | pleasing to have pattern guard bindings visible in where clauses? Or are | people more worried about the failures that would happen if you used a | binding from a pattern guard that ended up false? | | - Ravi | _______________________________________________ | Haskell-prime mailing list | Haskell-prime@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-prime

| Anyway, what do other people think? Do people besides me find it | pleasing to have pattern guard bindings visible in where clauses? Or are | people more worried about the failures that would happen if you used a | binding from a pattern guard that ended up false?
It sounds like there's a clear consensus against the idea, since it is too ugly in the presence of multiple where clauses. Consider the suggestion withdrawn. - Ravi
participants (3)
-
Lemmih
-
Ravi Nanavati
-
Simon Peyton-Jones