In `A new view of guards', Simon cited
> [2] W Burton, E Meijer, P Sansom, S Thompson, P Wadler, "A (sic) extension
> to Haskell 1.3 for views", sent to the Haskell mailing list
> 23 Oct 1996
Was that posted on this Haskell mailing list? Does anyone know where I could
get a copy of this proposal?
> I would really welcome feedback on this proposal
Here goes, ...
Reaction to Pattern Guards
==========================
* I am sure that I have been nobbled by the lack of pattern guards
regularly but have got used to clunking my way round the problem. I
think I could get comfortable with pattern guards quickly. I agree
(with Simon) that pattern guards look a much better bet than views.
* Putting guards into the where clause would break my declarative
and operational model of Haskell.
* Guards correspond (almost) to if-then-else expressions but this would
no longer be the case with pattern guards. Should Haskell have a
conditional that expresses this way of choosing?
* An aspect that I like of Haskell and the report is the translational
semantics used to account for most of its constructions, particularly
pattern matching. How would this work out?
My Own Gripe: if-then-else
==========================
I have longstanding dislike of Haskell's expression conditional:
* The use of keywords makes it visually unappealing and quite hard to
pick out if-then-else expressions, unless keywords are set in bold
face.
* The use of three keywords to express something that can be expressed
with a single function application seems extravagant.
* It is not easy to get a layout for if-then-else that is entirely
satisfactory. My standard format is
if test_expression
then success_part
else failure_part
which takes up three lines and allows either of the branch expressions
to spill onto successive lines, with each such line being a tab stop in
from the `if' column. The problem comes when several conditions are
present, provoking a rightward march. In this case I use
if test1 then
part1
else if test2 then
part2
else
part3
but I don't like it (the conditional expressions are not lined up and
they tend to be buried in thickets of else-if-then keywords).
* The interaction between if-then-else and do layout doesn't always work
out so well -- the first arrangement above works but the second one
doesn't (all of the expression must stay on the right of the opening
`if' when the conditional is used as a `do' statement, otherwise layout
will terminate the statement early). The following is wrong:
do if test1 then
part1
else if test2 then
part2
else
part3
This seems to be a gotcha for non-expert Haskell users.
Sometimes I have felt tempted to write
case test_expression of
True -> success_part
False -> failure_part
(and I know somebody who *does* do this) or even
case () of
() | test1 -> part1
| test2 -> part2
| otherwise -> part3
which has led me to wonder about an alternative `if' syntax.
An Alternative Conditional
==========================
Proposal: add the following conditional expression:
case
| test1 -> part1
| test2 -> part2
| otherwise -> part3
It works well with multi-way conditionals and `do' expressions; it is easy to
lay out; it stands out visually; it almost looks as if it is there already.
The layout rule shouldn't be needed here.
I suspect that the syntax should force the last clause to be an `otherwise'
conditional, entailing the conversion of `otherwise' to full keyword-hood. As
such, if existing programs redefined `otherwise' or used them in non-guard
contexts then they would be broken, but easily fixable. Otherwise it should be
upwards compatible with Haskell 1.4. if-then-else could be phased out (or
retained I suppose).
Of course, this syntax would pave the way for including pattern guards in
conditionals.
Pattern Guards and Conditionals
===============================
If case conditionals were added at the same time as pattern guards, would they
make it any easier to account for them? I suspected so and tried it out.
(This is a first cut; I am sure it can be improved.)
Syntax
------
The following productions would be added to the syntax (`exp^10' is extended;
`alt' and `gdpat' supplant the existing ones; `quals' and `cgdpat' are new).
@@@
exp^{10} -> \cdots
| case cgdpat
\cdots
alt -> pat @->@ exp [@where@ decllist]
| pat (gdpat|cgdpat) [@where@ decllist]
quals -> qual \{ @,@ qual \}
gdpat -> @|@ quals @->@ exp [ gdpat ]
cgdpat -> gdpat @|@ @otherwise@ @->@ exp
@@@@
Note that guarded patterns (gdpat) and complete guarded patterns (cgdpat) are
being distinguished syntactically. I say that this is a good thing as there is
an important semantic difference.
Semantics: Case Expressions
---------------------------
These rules would replace rule (c) of `Semantics of Case Expressions' in the
Haskell report. [Incidentally, I think there is a problem with the placement
of ';'s in this rule in the report.]
Rule (c)(i): completing alternatives
case v of { p | g where { decls }; _ -> e }
= case e of { y -> (where y is a completely new variable)
case v of { p | g | otherwise -> y where { decls }; _ -> y }}
where `| g' is a guarded pattern (gdpat)
Rule (c)(ii): separating (complete) guards from alternatives
case v of { p | cg where { decls }; _ -> e }
= case v of { p -> let { decls } in case | cg; _ -> e }
where `| cg' is a complete guarded pattern (cgdpat)
The first rule converts incomplete guards into equivalent complete guards and
the second rule lifts complete guards into conditionals.
Semantics: Conditionals
-----------------------
These are easy enough.
(a) convert to standard form
case | g_1 -> e_1
| ...
| otherwise -> e
= (\v -> case | True, g_1 -> e_1
| ...
| otherwise -> v) e
where v is a completely new variable
(b) convert into two way conditionals
case | g_1 -> e_1
| ...
| otherwise -> v
= case | g_1 -> e_1
| otherwise ->
case | ...
| otherwise -> v
(c) eliminate guard qualifiers
case | qs, e' -> e
| otherwise -> v
= case | qs, True <- e' -> e
| otherwise -> v
(d) eliminate let qualifiers
case | qs, let { decls } -> e
| otherwise -> v
= case | qs -> let { decls } in e
| otherwise -> v
(e) eliminate pattern qualifiers
case | qs, p <- e' -> e
| otherwise -> v
= case | qs -> case e' of { p -> e; _ -> v }
| otherwise -> v
(f) done
case | True -> e
| otherwise -> v
= e
Conclusion
==========
It looks as if case conditionals may help explain pattern guards in separating
them out from the pattern matching machinery. In doing so it would make for a
more uniform treatment of a new construct in addition to cleaning up the older
if-then-else expressions.
Chris Dornan [EMAIL PROTECTED]
University College Cork +353 21 902837