Pattern guards vs. case (was, unfortunately :Re: interesting example of laziness/ghc optimisation)

2001-03-01 Thread Ketil Malde


(Apologies, I forgot to change the subject)

Laszlo Nemeth [EMAIL PROTECTED] writes:

 * * * Ketil Malde [EMAIL PROTECTED] wrote:

 There is no difference. The 'pipe-syntax' (or pattern guards) gets
 desugared (by the pattern matching compiler) to case statements i.e.:

 runRandom = \ last max num.case (num  1) of
  True  - runRandom (fst new) max (num-1)
  False - snd new

But - the converse is not true, is it?  I can write

 ... = case foo of
(Foo f) - ...
(Bar b) - ...

but I can't express that as a pattern-guarded expression, can I?  My
impression here is that the PG syntax adds nothing, and is hardly any
more readable, and less intuitive for migrators from more traditional
language.  Why is it there at all?  Is there a (rough) guideline for
when to use one or the other?

 For a more detailed discussion see SPJ's book, Augustsson original
 paper, or M Pettersen't thesis (LNCS 1549). 

Okay, I'll try to look them up.

-kzm
-- 
If I haven't seen further, it is by standing in the footprints of giants

___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell



Re: Pattern guards vs. case (was, unfortunately :Re: interesting example of laziness/ghc optimisation)

2001-03-01 Thread John Meacham

On Thu, Mar 01, 2001 at 09:40:48AM +0100, Ketil Malde wrote:
 
 (Apologies, I forgot to change the subject)
 
 Laszlo Nemeth [EMAIL PROTECTED] writes:
 
  * * * Ketil Malde [EMAIL PROTECTED] wrote:
 
  There is no difference. The 'pipe-syntax' (or pattern guards) gets
  desugared (by the pattern matching compiler) to case statements i.e.:
 
  runRandom = \ last max num.case (num  1) of
   True  - runRandom (fst new) max (num-1)
   False - snd new
 
 But - the converse is not true, is it?  I can write
 
  ... = case foo of
 (Foo f) - ...
 (Bar b) - ...
 
 but I can't express that as a pattern-guarded expression, can I?  My
 impression here is that the PG syntax adds nothing, and is hardly any
 more readable, and less intuitive for migrators from more traditional
 language.  Why is it there at all?  Is there a (rough) guideline for
 when to use one or the other?


this is because pattern guards are not the same as case statements, they
do not do matching and deconstruction of values, but rather are boolean
expressions to be checked _in order_ to determine whether to use that
function body or not. 

imagine 

f n | n  0 = -1
f n | n  5 = 1
f n = 2

this cannot be expressed as a single case statement because you cannot
match 'n' against an expression. (just like you cannot deconstruct a
value in a boolean expression as your above example demonstrates)

this translates to nested if statements rather than a single case
statement. what is confusing is that if statements can be constructed
from case statements too... the above translates to

f n = if n  0 then -1 else if n  5 then 1 else 2

or in case notation 

case n  0 of
 True - -1 
 False - case n  5 of
True - 1
False - 2

note you will need many nested case statements to deal with patter
guards, they are not equivalent to a single case statement. 

in the core language 'case' is the ONLY alternation primitive so
everything can translate to it at some point. pattern guards are useful
because otherwise you end up with heavily nested if or case statements
which are definately less readable than the pattern-guard syntax.

hint: read '|' as 'such that' so
f n | n  0 = ... reads "f of n such that n is less than zero is
..."
note also that the vertical bar interpreted in this way also
has mathematical precident so its not completely arbitrary.


Hope this helps and that I am not utterly wrong :)

John

-- 
--
John Meacham   http://www.ugcs.caltech.edu/~john/
California Institute of Technology, Alum.  [EMAIL PROTECTED]
--

___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell



Re: Pattern guards vs. case (was, unfortunately :Re: interesting example of laziness/ghc optimisation)

2001-03-01 Thread Laszlo Nemeth

* * * Ketil Malde [EMAIL PROTECTED] wrote:

 ut - the converse is not true, is it?  I can write
 
 ... = case foo of
(Foo f) - ...
(Bar b) - ...
 
 ut I can't express that as a pattern-guarded expression, can I?

You probably have already seen John's reply which pretty much says
everything. But if you want to be really weird you can write something
like (I haven't typed this in):

f x | (Foo _) == x = 
f x | (Bar _) == x =

which doesn't buy you anything because it doesn't bind the argument of
Foo to anything. There were a couple of messages a year or so ago
about what can be done with pattern matching and I recall Simon Marlow
posted a few puzzling examples.

 Why is it there at all?  Is there a (rough) guideline for when to
 use one or the other?

Sugar ... but I think in this case is not the 'unhealthy' variety. As
John noted, without it you would have to write nested case statements
which is cumbersome and may lead to suboptimal code i.e. code
duplication and repeated tests (assuming later stages of your compiler
doesn't rearrange the code). In fact, the entire issue of compilation
of pattern matching arises from the desire to select the appropriate
rhs with the minimum number of tests.

Rough guideline? I use guards whenever I can (which means not at all
these days since SML sadly lacks guards (for a good reason!)), because
I find it easy to read it and I hope that a clever pattern matching
compiler takes advantage of the extra information.

--laszlo

___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell