proposal: introduce lambda-match (explicit match failure and
fall-through)
Claus Reinke
claus.reinke at talk21.com
Tue Oct 24 05:49:07 EDT 2006
name:
introduce lambda-match (explicit match failure and fall-through)
summary:
Haskell 98 provides *two different translations* of lambda
abstractions involving pattern matching, only one of which is
directly accessible (Section 3.3 - the other is embedded in the
translation of do-notation, see "ok" in Section 3.14).
providing explicit source notation for the second translation,
substantially simplifies programmability of pattern-match
fall-through by reification of pattern-match failure, two
central language features that are so far only available
through the built-in, non-composable case construct.
what:
in Section 3.3, the translation for conventional lambda
abstractions with patterns is given as
[| \p1 .. pn-> e |] = \x1 .. xn-> case (x1,..,xn) of (p1,..,pn) -> e
with xi fresh identifiers, and pattern-match failure resulting in
_|_. the latter is unfortunate, and results in partial functions the
coverage of which cannot be combined, but it is forced by
translation into conventional lambda calculus.
since computational lambda calculus (\-M) has become a central part
of Haskell programming practice, there shall be an alternative form
of lambda abstraction, dubbed here lambda-match, with associated
translation into \-M:
[| |p1 .. pn-> e |] = \x1 .. xn-> case (x1,..,xn) of
{ (p1,..,pn) -> return e;
_ -> fail "no match" }
[note1: this is the translation in principle - in practice, to
enable composition of lambda-matches without further language
extensions, a slight modification is needed, wrapping the right-hand
sides of the case in a Match constructor, see library and patch]
a library for composing these lambda-matches shall provide for
composition of alternative lambda-matches (+++), match failure
(nomatch) and embedding of the explicit match monad into pure
expressions (splice, where "splice |p1..pn->e = \p1..pn->e").
[note2: an alternative translation would use do-notation instead
of case as the target:
[| |p1 .. pn-> e |] = \x1 .. xn-> do {
(p1,..,pn) <- return (x1,..,xn);
return e }
both translations easily accomodate guards and pattern guards
as well, the former by building on existing support for these two
features in case constructs, the latter without requiring any
previous implementation of pattern guards, by lifting (pattern)
guards into the match monad]
implementation impact:
minimal - limited to an extension in parser/desugarer, employing
previously inaccessible syntax for lambda-match, and a slight
variation of the existing lambda translation; also adds a small
library to support composition of matches.
[note3: a first draft of the composition library and a patch for
GHC (about a dozen new lines in the parser) are provided as
attachments to this proposal, together with some examples]
context:
as has been pointed out in the thread on replacing and improving
pattern guards, Haskell's pattern matching support, even before
pattern guards, is monolithic (built-in case is the only way to handle
multiple alternative matches) rather than compositional (lambdas
represent individual alternatives, but cannot be composed on
match fall-through). this implies increased complexity of the language
definition and limited expressiveness of its features, when compared
with alternative models (eg, adapting Wolfram's pattern match
calculus for Haskell). see, eg.:
http://www.haskell.org/pipermail/haskell-prime/2006-October/001713.html
http://www.haskell.org/pipermail/haskell-prime/2006-October/001720.html
http://www.haskell.org/pipermail/haskell-prime/2006-October/001723.html
http://www.haskell.org/pipermail/haskell-prime/2006-October/001724.html
in principle, replacing Haskell's current pattern matching support
with a simpler, more compositional model, and defining the current
constructs on top of that new core is the way forward, IMHO. in
practice, however, I suspect that the committee is less than tempted
to introduce such a substantial simplification for Haskell'.
the present proposal is an attempt at a compromise, suggesting a
minimal language change to introduce compositional pattern-match
failure and fall-through. with lambda-match, it implements only a
single language extension (as syntactic sugar), delegating the rest
of the functionality to a library. without the sugar, the result of the
by-hand translation becomes so hard to read as to be near
unusable, while the chosen form of sugaring allows to provide
most of the language features discussed in the earlier threads to
be provided as a library. this does seem to be a useable balance.
building constructs of the simpler pattern-match model on top of
the more complex one is somewhat irksome from a language design
perspective, but does at least gain the expressiveness of the simpler
model. if programmers make substantial use of this new functionality
in Haskell' (as I strongly suspect they will - I have been doing similar
translations by hand for some time now), it will be up to Haskell'' to
turn the table, and to define the current complex model on top of a
compositional one.
as a preview of this anticipated language refactoring;), it is instructive
to compare the two alternative translations of lambda-match sketched
above:
- the first directly builds on the existing, complex case constructs
with their built-in (pattern) guards and match fall-through support;
this eases adding the new, simpler features to implementations
that support the old, complex ones (like GHC), but completely
foregoes any attempt to simplify those implementations in the
process; [the attached patch for GHC follows this route]
- the second translation avoids any direct reference to case,
employing do-notation instead; this requires slightly more
effort, eg. in translating pattern guards into the match monad,
but is eminently suitable for adding the new features to
implementations that do not support pattern guards yet, or
that simply want to reduce the number of built-in constructs.
[patchers for Hugs, etc., might want to follow this route?]
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ControlMonadMatch.hs
Type: application/octet-stream
Size: 2364 bytes
Desc: not available
Url : http://www.haskell.org/pipermail/haskell-prime/attachments/20061024/20d2a681/ControlMonadMatch-0001.obj
-------------- next part --------------
A non-text attachment was scrubbed...
Name: LambdaMatchExamples.hs
Type: application/octet-stream
Size: 2934 bytes
Desc: not available
Url : http://www.haskell.org/pipermail/haskell-prime/attachments/20061024/20d2a681/LambdaMatchExamples-0001.obj
-------------- next part --------------
A non-text attachment was scrubbed...
Name: LambdaMatch.hunk
Type: application/octet-stream
Size: 895 bytes
Desc: not available
Url : http://www.haskell.org/pipermail/haskell-prime/attachments/20061024/20d2a681/LambdaMatch-0001.obj
More information about the Haskell-prime
mailing list