
I have a tricky little question... Suppose I write a function like this: foo pattern1 | gard1 = ... | gard2 = ... foo pattern2 | gard3 = ... | gard4 = ... According to one tutorial I read, if pattern1 matches, pattern2 will never be tried, even if both guard1 and guard2 fail. And according to another tutorial I read, if pattern1 matches but all guards fail, pattern2 *will* be tried. Can somebody comfirm which one is actually correct?

On Wed, Jun 27, 2007 at 09:46:41PM +0100, Andrew Coppin wrote:
I have a tricky little question...
Suppose I write a function like this:
foo pattern1 | gard1 = ... | gard2 = ... foo pattern2 | gard3 = ... | gard4 = ...
According to one tutorial I read, if pattern1 matches, pattern2 will never be tried, even if both guard1 and guard2 fail.
And according to another tutorial I read, if pattern1 matches but all guards fail, pattern2 *will* be tried.
Can somebody comfirm which one is actually correct?
According to http://haskell.org/onlinereport/exps.html#sect3.17.2 Top level patterns in case expressions and the set of top level patterns in function or pattern bindings may have zero or more associated guards. A guard is a boolean expression that is evaluated only after all of the arguments have been successfully matched, and it must be true for the overall pattern match to succeed. The environment of the guard is the same as the right-hand-side of the case-expression alternative, function definition, or pattern binding to which it is attached. So, if guard1 and guard2 both fail, then pattern1 doesn't match (and pattern matching continues). As such, your "corner case" cannot actually exist. Stefan

Stefan O'Rear wrote:
On Wed, Jun 27, 2007 at 09:46:41PM +0100, Andrew Coppin wrote:
I have a tricky little question...
Suppose I write a function like this:
foo pattern1 | gard1 = ... | gard2 = ... foo pattern2 | gard3 = ... | gard4 = ...
According to one tutorial I read, if pattern1 matches, pattern2 will never be tried, even if both guard1 and guard2 fail.
And according to another tutorial I read, if pattern1 matches but all guards fail, pattern2 *will* be tried.
Can somebody comfirm which one is actually correct?
According to http://haskell.org/onlinereport/exps.html#sect3.17.2
Top level patterns in case expressions and the set of top level patterns in function or pattern bindings may have zero or more associated guards. A guard is a boolean expression that is evaluated only after all of the arguments have been successfully matched, and it must be true for the overall pattern match to succeed. The environment of the guard is the same as the right-hand-side of the case-expression alternative, function definition, or pattern binding to which it is attached.
So, if guard1 and guard2 both fail, then pattern1 doesn't match (and pattern matching continues). As such, your "corner case" cannot actually exist.
Wow, wait a sec - case expressions are allowed to have guards too??

On Wed, Jun 27, 2007 at 10:28:05PM +0100, Andrew Coppin wrote:
Stefan O'Rear wrote:
On Wed, Jun 27, 2007 at 09:46:41PM +0100, Andrew Coppin wrote:
I have a tricky little question...
Suppose I write a function like this:
foo pattern1 | gard1 = ... | gard2 = ... foo pattern2 | gard3 = ... | gard4 = ...
According to one tutorial I read, if pattern1 matches, pattern2 will never be tried, even if both guard1 and guard2 fail.
And according to another tutorial I read, if pattern1 matches but all guards fail, pattern2 *will* be tried.
Can somebody comfirm which one is actually correct?
According to http://haskell.org/onlinereport/exps.html#sect3.17.2
Top level patterns in case expressions and the set of top level patterns in function or pattern bindings may have zero or more associated guards. A guard is a boolean expression that is evaluated only after all of the arguments have been successfully matched, and it must be true for the overall pattern match to succeed. The environment of the guard is the same as the right-hand-side of the case-expression alternative, function definition, or pattern binding to which it is attached.
So, if guard1 and guard2 both fail, then pattern1 doesn't match (and pattern matching continues). As such, your "corner case" cannot actually exist.
Wow, wait a sec - case expressions are allowed to have guards too??
stefan@stefans:~$ ghci Loading package base ... linking ... done. ___ ___ _ / _ \ /\ /\/ __(_) / /_\// /_/ / / | | GHC Interactive, version 6.7.20070612, for Haskell 98. / /_\\/ __ / /___| | http://www.haskell.org/ghc/ \____/\/ /_/\____/|_| Type :? for help. Prelude> case () of { () | True -> "x" } "x" Prelude> Stefan

On Wednesday 27 June 2007, Andrew Coppin wrote:
Stefan O'Rear wrote:
On Wed, Jun 27, 2007 at 09:46:41PM +0100, Andrew Coppin wrote:
I have a tricky little question...
Suppose I write a function like this:
foo pattern1
| gard1 = ... | gard2 = ...
foo pattern2
| gard3 = ... | gard4 = ...
According to one tutorial I read, if pattern1 matches, pattern2 will never be tried, even if both guard1 and guard2 fail.
And according to another tutorial I read, if pattern1 matches but all guards fail, pattern2 *will* be tried.
Can somebody comfirm which one is actually correct?
According to http://haskell.org/onlinereport/exps.html#sect3.17.2
Top level patterns in case expressions and the set of top level patterns in function or pattern bindings may have zero or more associated guards. A guard is a boolean expression that is evaluated only after all of the arguments have been successfully matched, and it must be true for the overall pattern match to succeed. The environment of the guard is the same as the right-hand-side of the case-expression alternative, function definition, or pattern binding to which it is attached.
So, if guard1 and guard2 both fail, then pattern1 doesn't match (and pattern matching continues). As such, your "corner case" cannot actually exist.
Wow, wait a sec - case expressions are allowed to have guards too??
Yes. I guess I assumed you knew that, sorry. The only syntactic (or semantic) difference between function equations and case expressions (aside from the fact that case expressions require you to tuple up the values you're pattern-matching on) is the fact that case expressions use -> where function bindings use =. Other than that, the two forms are exactly equivalent. Sincerely, Jonathan Cast http://sourceforge.net/projects/fid-core http://sourceforge.net/projects/fid-emacs

Andrew: Try using catchalls in your guards
pattern1
| guard1 =
| guard2 =
| otherwise =
This makes it much easier to use pattern guards.
"otherwise" is a reserved word used for this stuff in ghc.
-Dan
On 6/27/07, Jon Cast
Stefan O'Rear wrote:
On Wed, Jun 27, 2007 at 09:46:41PM +0100, Andrew Coppin wrote:
I have a tricky little question...
Suppose I write a function like this:
foo pattern1
| gard1 = ... | gard2 = ...
foo pattern2
| gard3 = ... | gard4 = ...
According to one tutorial I read, if pattern1 matches, pattern2 will never be tried, even if both guard1 and guard2 fail.
And according to another tutorial I read, if pattern1 matches but all guards fail, pattern2 *will* be tried.
Can somebody comfirm which one is actually correct?
According to http://haskell.org/onlinereport/exps.html#sect3.17.2
Top level patterns in case expressions and the set of top level
On Wednesday 27 June 2007, Andrew Coppin wrote: patterns
in function or pattern bindings may have zero or more associated guards. A guard is a boolean expression that is evaluated only after all of the arguments have been successfully matched, and it must be true for the overall pattern match to succeed. The environment of the guard is the same as the right-hand-side of the case-expression alternative, function definition, or pattern binding to which it is attached.
So, if guard1 and guard2 both fail, then pattern1 doesn't match (and pattern matching continues). As such, your "corner case" cannot actually exist.
Wow, wait a sec - case expressions are allowed to have guards too??
Yes. I guess I assumed you knew that, sorry.
The only syntactic (or semantic) difference between function equations and case expressions (aside from the fact that case expressions require you to tuple up the values you're pattern-matching on) is the fact that case expressions use -> where function bindings use =. Other than that, the two forms are exactly equivalent.
Sincerely, Jonathan Cast http://sourceforge.net/projects/fid-core http://sourceforge.net/projects/fid-emacs _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Wednesday 27 June 2007, you wrote:
Andrew: Try using catchalls in your guards
pattern1
| guard1 = | guard2 = | otherwise =
This makes it much easier to use pattern guards. "otherwise" is a reserved word used for this stuff in ghc.
Since we're quoting the standard and all, my inner pedant can't help but quibble: otherwise is not a keyword, it's a synonym for True defined in the Standard Prelude (and, in particular, goes away if you say import Prelude ()): $ cat > Foo.hs import Prelude main = print otherwise $ ghc Foo.hs -o foo $ ./foo True $ cat > Foo.hs import Prelude (print) main = print otherwise $ ghc Foo.hs -o foo Foo.hs:3:13: Not in scope: `otherwise' Sincerely, Jonathan Cast Computer Programmer http://sourceforge.net/projects/fid-core http://sourceforge.net/projects/fid-emacs

Dan Mead wrote:
Andrew: Try using catchalls in your guards
pattern1 | guard1 = | guard2 = | otherwise =
This makes it much easier to use pattern guards. "otherwise" is a reserved word used for this stuff in ghc.
Yeah, it's good practice to include an explicit otherwise clause - but in this specific instance, I'm trying to do tricky stuff where one rule falls through to another if some condition doesn't hold - but that condition is only expressible as a function. Well, let me show you the code - somebody will probably recognise this stuff... convert1 :: Expression -> Expression convert1 S = S convert1 K = K convert1 I = I convert1 (Var v) = Var v convert1 (x :@: y) = (convert1 x) :@: (convert1 y) convert1 (Lam n e) | n `not_in` e = K :@: (convert1 e) convert1 (Lam n (Var v)) | n == v = I | otherwise = K :@: (convert1 (Var v)) convert1 (Lam n (x :@: y)) | y `is_var` n && n `not_in` x = convert1 x | otherwise = S :@: (convert1 (Lam n x)) :@: (convert1 (Lam n y)) convert1 (Lam n (Lam m e)) | n `not_in` e = K :@: (convert1 (Lam m e)) | otherwise = convert1 (Lam n (convert1 (Lam m e)))

On Fri, Jun 29, 2007 at 07:18:00PM +0100, Andrew Coppin wrote:
Dan Mead wrote:
Andrew: Try using catchalls in your guards
pattern1 | guard1 = | guard2 = | otherwise =
This makes it much easier to use pattern guards. "otherwise" is a reserved word used for this stuff in ghc.
Yeah, it's good practice to include an explicit otherwise clause - but in this specific instance, I'm trying to do tricky stuff where one rule falls through to another if some condition doesn't hold - but that condition is only expressible as a function.
Well, let me show you the code - somebody will probably recognise this stuff...
convert1 :: Expression -> Expression convert1 S = S convert1 K = K convert1 I = I convert1 (Var v) = Var v convert1 (x :@: y) = (convert1 x) :@: (convert1 y) convert1 (Lam n e) | n `not_in` e = K :@: (convert1 e) convert1 (Lam n (Var v)) | n == v = I | otherwise = K :@: (convert1 (Var v)) convert1 (Lam n (x :@: y)) | y `is_var` n && n `not_in` x = convert1 x | otherwise = S :@: (convert1 (Lam n x)) :@: (convert1 (Lam n y)) convert1 (Lam n (Lam m e)) | n `not_in` e = K :@: (convert1 (Lam m e)) | otherwise = convert1 (Lam n (convert1 (Lam m e)))
This is *much* easier expressed as a bottom-up traversal. compile = transform optimize . transform eliminate eliminate (Lam v e) = transform (abstract v) e eliminate x = x abstract v (Var v') | v == v' = I abstract v (a :@ b) = S :@ a :@ b abstract v x = x optimize (S :@ (K :@ x) :@ (K :@ y)) = K :@ (x :@ y) optimize (S :@ (K :@ x) :@ I) = x optimize x = x (Here using Uniplate, mostly because it is the freshest in my mind of all of them). Stefan

Stefan O'Rear wrote:
On Fri, Jun 29, 2007 at 07:18:00PM +0100, Andrew Coppin wrote:
Well, let me show you the code - somebody will probably recognise this stuff...
convert1 :: Expression -> Expression convert1 S = S convert1 K = K convert1 I = I convert1 (Var v) = Var v convert1 (x :@: y) = (convert1 x) :@: (convert1 y) convert1 (Lam n e) | n `not_in` e = K :@: (convert1 e) convert1 (Lam n (Var v)) | n == v = I | otherwise = K :@: (convert1 (Var v)) convert1 (Lam n (x :@: y)) | y `is_var` n && n `not_in` x = convert1 x | otherwise = S :@: (convert1 (Lam n x)) :@: (convert1 (Lam n y)) convert1 (Lam n (Lam m e)) | n `not_in` e = K :@: (convert1 (Lam m e)) | otherwise = convert1 (Lam n (convert1 (Lam m e)))
This is *much* easier expressed as a bottom-up traversal.
compile = transform optimize . transform eliminate
eliminate (Lam v e) = transform (abstract v) e eliminate x = x
abstract v (Var v') | v == v' = I abstract v (a :@ b) = S :@ a :@ b abstract v x = x
optimize (S :@ (K :@ x) :@ (K :@ y)) = K :@ (x :@ y) optimize (S :@ (K :@ x) :@ I) = x optimize x = x
Woah... Let me sit down and grok that for an hour or two. o_o (Hey, maybe this is why I don't develop cutting edge software for a living?)
(Here using Uniplate, mostly because it is the freshest in my mind of all of them).
What's Uniplate?

Andrew Coppin
Woah... Let me sit down and grok that for an hour or two. o_o
The Haskell learning curve - including the wonderful range of useful generic stuff you can do with it - extends way higher than for many other languages, I think, though you can write lots of useful code when you're just partway up. I'm still learning things, and knowing I have much more yet to learn, and normally I can learn most of my way around a new programming language within a couple of weeks. (snip)
What's Uniplate?
http://www-users.cs.york.ac.uk/~ndm/uniplate/ may help to answer that question. I haven't even finished understanding SYB, yet, though; I'm still mystified by how to use Data.Generics.Twins.gzipWithQ. So, I'm not at a stage where I can usefully contrast Uniplate with the Data.Generics stuff. -- Mark

Hi
What's Uniplate?
http://www-users.cs.york.ac.uk/~ndm/uniplate/ may help to answer that question. I haven't even finished understanding SYB, yet, though; I'm still mystified by how to use Data.Generics.Twins.gzipWithQ. So, I'm not at a stage where I can usefully contrast Uniplate with the Data.Generics stuff.
Uniplate should be easier to understand than SYB. The draft paper on that web page compares Uniplate to SYB (and Compos). It also has plenty of examples of how to use Uniplate to do tasks. The manual on that page has suggested exercises to check that you can understand and extend Uniplate code. Uniplate produces more concise code, has traversal operations that are not present in the SYB library, runs faster and works in Hugs. SYB is capable of many more generic operations than Uniplate, such as gzipWithQ and much much more. Thanks Neil

Stefan O'Rear wrote:
This is *much* easier expressed as a bottom-up traversal.
compile = transform optimize . transform eliminate
eliminate (Lam v e) = transform (abstract v) e eliminate x = x
abstract v (Var v') | v == v' = I abstract v (a :@ b) = S :@ a :@ b abstract v x = x
optimize (S :@ (K :@ x) :@ (K :@ y)) = K :@ (x :@ y) optimize (S :@ (K :@ x) :@ I) = x optimize x = x
(Here using Uniplate, mostly because it is the freshest in my mind of all of them).
Um... shouldn't that read abstract v (a :@ b) = S :@ (transform (abstract v) a) :@: (transform (abstract v) b) ? Or am I missing something?

On Sun, Jul 01, 2007 at 05:06:10PM +0100, Andrew Coppin wrote:
Stefan O'Rear wrote:
This is *much* easier expressed as a bottom-up traversal.
compile = transform optimize . transform eliminate
eliminate (Lam v e) = transform (abstract v) e eliminate x = x
abstract v (Var v') | v == v' = I abstract v (a :@ b) = S :@ a :@ b abstract v x = x
optimize (S :@ (K :@ x) :@ (K :@ y)) = K :@ (x :@ y) optimize (S :@ (K :@ x) :@ I) = x optimize x = x
(Here using Uniplate, mostly because it is the freshest in my mind of all of them).
Um... shouldn't that read
abstract v (a :@ b) = S :@ (transform (abstract v) a) :@: (transform (abstract v) b)
No, because the whole point of transform is that it handles recursion for you. (However, there is a bug! abstracting an unrecognized form (that is, a primitive combinator) should add a K.) Stefan

Stefan O'Rear wrote:
On Sun, Jul 01, 2007 at 05:06:10PM +0100, Andrew Coppin wrote:
Um... shouldn't that read abstract v (a :@ b) = S :@ (transform (abstract v) a) :@: (transform (abstract v) b)
No, because the whole point of transform is that it handles recursion for you.
OK. Well in that case, I have no idea what transform is doing... (I assumed it was just applying some function to every part of the structure - but that wouldn't solve this case.)
(However, there is a bug! abstracting an unrecognized form (that is, a primitive combinator) should add a K.)
I'm going to have to take some time to bend my mind around that one too... (Does anybody else on this list frequently get the feeling their IQ is just too low for Haskell??)

Mark T.B. Carroll wrote:
Andrew Coppin
writes: (snip) (Does anybody else on this list frequently get the feeling their IQ is just too low for Haskell??)
I do. But then, when I finally understand something, it seems easy and simple and I'm not sure why it wasn't obvious all along.
*cough* monads *cough* ;-)

On 7/1/07, Andrew Coppin
(Does anybody else on this list frequently get the feeling their IQ is just too low for Haskell??)
That's the best part of learning Haskell. You're always in touch with the very best people --- directly or indirectly (i.e. using their libraries and documentation). -- Felipe.

Felipe Almeida Lessa wrote:
On 7/1/07, Andrew Coppin
wrote: (Does anybody else on this list frequently get the feeling their IQ is just too low for Haskell??)
That's the best part of learning Haskell. You're always in touch with the very best people --- directly or indirectly (i.e. using their libraries and documentation).
I know what you mean... (Personally, I am still in awe of people who write Haskell programs that are *thousands* of lines long. I mean, like, wow!)

2007/7/1, Andrew Coppin
I'm going to have to take some time to bend my mind around that one too...
(Does anybody else on this list frequently get the feeling their IQ is just too low for Haskell??)
I do. Sometimes when I find myself doing some type hackery. And that's a sad feeling. Not because I realise that my IQ is lower than it could be, but because the whole idea of Haskell is doing things fast and easily. While on that I can spend quite a lot of time. But that's only that fragment of work. The rest goes well :) When I do that, I may think "hey, seems like in Java I'd do that pretty quickly without a lot of thinking" but then you realise that you're striving for much more that you'd got in Java. Much more static garantees, so the comparison isn't correct at all.

Jon Cast wrote:
On Wednesday 27 June 2007, Andrew Coppin wrote:
Wow, wait a sec - case expressions are allowed to have guards too??
Yes. I guess I assumed you knew that, sorry.
The only syntactic (or semantic) difference between function equations and case expressions (aside from the fact that case expressions require you to tuple up the values you're pattern-matching on) is the fact that case expressions use -> where function bindings use =. Other than that, the two forms are exactly equivalent.
I knew they were nearly identical. I didn't realise that they *were* identical! Hmm, I tried to find out 1 thing and actually found out 2 things! :-D I wonder what the layout for that is... something like this? case foo of patter1 | guard1 -> ... | guard2 -> ... pattern2 | guard3 -> ... | guard4 -> ... Well, I'll have to go try it... I always thought of guards as being a nice shorthand for if-expressions - but if they can affect the order of pattern matching, clearly they are more drastically different than I realised. (Generally, I never ever use 'em!)

Andrew Coppin writes:
I wonder what the layout for that is... something like this?
case foo of patter1 | guard1 -> ... | guard2 -> ... pattern2 | guard3 -> ... | guard4 -> ...
Something like that should work. If the patterns are more indented than the 'case', and the guards are more indented than the patterns, then the layout rule should work fine. As always, once you get used to the way layout works, everything is pretty intuitive.
Well, I'll have to go try it...
Always a nice solution to these kinds of problems!
I always thought of guards as being a nice shorthand for if-expressions - but if they can affect the order of pattern matching, clearly they are more drastically different than I realised. (Generally, I never ever use 'em!)
A useful rule to remember with guards is that "once you cross the equals sign, you can't go back". So if one of your patterns matches and a guard on that pattern is true, that right-hand side will be evaluated and there is no way to fall back to another guard or pattern. -- -David House, dmhouse@gmail.com

On Friday 29 June 2007, Andrew Coppin wrote:
Jon Cast wrote:
On Wednesday 27 June 2007, Andrew Coppin wrote:
Wow, wait a sec - case expressions are allowed to have guards too??
Yes. I guess I assumed you knew that, sorry.
The only syntactic (or semantic) difference between function equations and case expressions (aside from the fact that case expressions require you to tuple up the values you're pattern-matching on) is the fact that case expressions use -> where function bindings use =. Other than that, the two forms are exactly equivalent.
I knew they were nearly identical. I didn't realise that they *were* identical!
Hmm, I tried to find out 1 thing and actually found out 2 things! :-D
I wonder what the layout for that is... something like this?
case foo of patter1
| guard1 -> ... | guard2 -> ...
pattern2
| guard3 -> ... | guard4 -> ...
Just so. Jonathan Cast http://sourceforge.net/projects/fid-core http://sourceforge.net/projects/fid-emacs

Hello Andrew, Thursday, June 28, 2007, 1:28:05 AM, you wrote:
Wow, wait a sec - case expressions are allowed to have guards too??
btw, it's used to implement boolean switches: case () of _ | a>0 -> 1 | a<0 -> -1 | otherwise -> 0 -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

On Wednesday 27 June 2007, Andrew Coppin wrote:
I have a tricky little question...
Suppose I write a function like this:
foo pattern1
| gard1 = ... | gard2 = ...
foo pattern2
| gard3 = ... | gard4 = ...
According to one tutorial I read, if pattern1 matches, pattern2 will never be tried, even if both guard1 and guard2 fail.
And according to another tutorial I read, if pattern1 matches but all guards fail, pattern2 *will* be tried.
Can somebody comfirm which one is actually correct?
You could just try it, you know . . . Anyway, the second tutorial is correct: if all guards on pattern1 fail, pattern2 will be tried next. See Section 3.17.3 in the Haskell Report [1]. Btw., which was the first tutorial? Sincerely, Jonathan Cast http://sourceforge.net/projects/fid-core http://sourceforge.net/projects/fid-emacs [1] http://haskell.org/onlinereport/exps.html#case-semantics
participants (10)
-
Andrew Coppin
-
Bulat Ziganshin
-
Dan Mead
-
Daniil Elovkov
-
David House
-
Felipe Almeida Lessa
-
Jon Cast
-
mark@ixod.org
-
Neil Mitchell
-
Stefan O'Rear