\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename fmatch.info @settitle Fare-matcher 1.0.0 @c %**end of header @copying This manual is for Fare-matcher, version 1.0.0. Copyright @copyright{} 2009 Fran@,{c}ois-Ren@'e Rideau and Robert P. Goldman. @quotation Permission is granted to ... @end quotation @end copying @titlepage @title Fare-Matcher Manual @subtitle ML-Style Matching in Common Lisp @author Fran@,{c}ois-Ren@'e Rideau and Robert P. Goldman @c The following two commands @c start the copyright page. @page @vskip 0pt plus 1filll @insertcopying Published by ... @end titlepage @c So the toc is printed at the start. @contents @ifnottex @node Top, Matching macros, (dir), (dir) @top Fare-Matcher Manual This manual is for Fare-matcher, version 1.0.0. @end ifnottex Fare-matcher adds constructs for Lisp2 pattern matching or destructuring. Lisp2 style means that instead of writing @example (destructuring-bind (a b (c d ()) . e) foo (bar a b c d e)) @end example You'd write @example (letm (list* a b (list c d ()) e) foo (bar a b c d e)) @end example @menu * Matching macros:: * Pattern language:: * Examples:: * Design notes:: * Function Index:: @end menu @node Matching macros, Pattern language, Top, Top @comment node-name, next, previous, up @chapter Matching macros Use these macros in your code: @deffn {Matching macro} ifmatch n m e e @example (ifmatch (cons a b) '(1) (list a b) -> (1 nil) @end example @end deffn @deffn {Matching macro} match m case-clauses @example (match msg (:ping (reply :pong)) ((:add a b) (reply `(result ,(+ a b))) (:quit (reply :bye))) @end example @end deffn @deffn {Matching macro} ematch m case-clauses Like @code{match}, but raises an error if no clause matches. @end deffn @deffn {Matching macro} letm pattern form lexical-scoped-body @example (letm (values (accessor* ((like-when msg (keywordp msg)) command)) err?) (read-command) (if err? "ouch" (list msg))) @end example @end deffn There are others. @node Pattern language, Examples, Matching macros, Top @comment node-name, next, previous, up @chapter Pattern language Patterns are lisp forms. Symbols in patterns match anything creating a binding to what they match, except @code{*} or @code{_} will match anything but are not bound. Literals are matched using @code{eq}. The core pattern matching forms are look like the forms for consing up things and match what otherwise they would create: @code{list}, @code{list*}, @code{values}, @code{cons}, and @code{vector}. Quite concise is that for most common lisp implementations you may use back-quoted forms. @example (match msg (`(+ ,a ,b) (+ a b)) (`(- ,a ,b) (- a b)) (`(- ,a) (- a b))) @end example Two forms @code{slot*}, @code{accessor*} allow you to match CLOS objects using the slot-names or the accessors respectively. For example: @example (defun window-hieght (window) (letm (slot* (top a) (bottom b)) window (- bottom top))) @end example Finally a few pattern forms provide for special cases: @code{and}, @code{or}, @code{of-type}, @code{like-when}. @node Examples, Design notes, Pattern language, Top @comment node-name, next, previous, up @chapter Examples Some samples pulled from a test case: @example (ifmatch (cons * (cons x y)) '(1 (2 3) 4) (list x y)) ==> ((2 3) (4)) (ifmatch (like-when (cons x y) (eql x y)) '(2 . 2) x) ==> 2 (ifmatch (and (cons x y) (when (eql x y))) '(2 . 2) x) ==> 2 (ifmatch (and (cons a 1) (cons 2 b)) '(2 . 1) (list a b)) ==> (2 1) (ifmatch (list a b) '(1 2) (list b a)) ==> (2 1) (ifmatch (list* a b c) '(1 2 3 4) (list a b c)) ==> (1 2 (3 4)) (ifmatch (and x (cons (of-type integer) *)) '(2) x) => (2) (defun my-length (x) (ematch x ((cons * tail) (1+ (my-length tail))) ('nil 0)) (my-length '(1 2 3)) ==> 3 @end example @node Design notes, Function Index, Examples, Top @comment node-name, next, previous, up @chapter Design notes This is my attempt at a pattern matcher. @menu * Design Goals:: * To Do List:: * Notes from the code:: @end menu @node Design Goals, To Do List, Design notes, Design notes @comment node-name, next, previous, up @section Semantic Design goals: @itemize @item ML- or Erlang-like semantics for pattern matching. @item Integration to the lexical environment: Variables in a match pattern are bound lexically around the form's body. @item Unlike destructuring-bind, follow the same Lisp2 paradigm of source-level lists specifying a generic pattern to call and its arguments. This also allows to trivially distinguish between variables and pattern names by a simple syntactic positional criterion. @item Extensibility through definition of new generic patterns, either functions or macros, by defining new names or having algebraic designators. @item No backtracking or unification, but leaving possibility for such thing as an extension. @end itemize Implementation goals: @itemize @item macro-expansion-time transformation of pattern into recognizing code. @item This first version is no frills: no attempt at algorithmic efficiency, optimization or backtracking. @item Optimized for human simplicity. @item Highly-factored using higher-order functions and macros. @item Underlying control structures are to be abstract enough so that backtracking could be added by replacing them. @end itemize Implementation choices: @itemize @item the @code{(ifmatch pattern form body...)} macro expands into a @code{(let (,@@vars) (when (funcall ,matcher ,form) ,@@body))} where (pattern-matcher pattern) returns (values matcher vars) @item matching code uses matcher-passing style - that's good. @item macro-expansion code uses a direct synthesis technique - that's bad. It means that all bindings for the match are common to all the matching forms, which requires a bit of discipline from writers of LIKE-WHEN clauses so that nothing evil should happen. Instead, we should use a monadic lexical-environment-passing-style that would create bindings as the match progresses. @item not much of any error detection is done, and when there is, error reporting is minimal. @item not any pattern optimization is done by the matching macros (however, since patterns are expanded into lisp code at macro-expansion time, the compiler might still do a few optimizations and produce reasonable code). @end itemize @node To Do List, Notes from the code, Design Goals, Design notes @comment node-name, next, previous, up @section To Do list: @itemize @item add a special case for (values) at the top level (???) @item add better patterns for matching structures and classes @item add macros for defining simple patterns of patterns, both in matching and in building. @item add lots of error checking @item make for a better propagation of bindings within internal clauses of the pattern matcher (due to like-when). -- binding-passing style(?) @item add non-linearity??? @item add backtracking, based on a CPS transform??? Or use Screamer? @item add first-class patterns (?) @item add pattern merging and optimization (!?) or maybe declarations? Factor the matching of identical initial patterns. @item add better documentation about the pattern matcher (???) @item add support for documentation strings in pattern defining forms @item add support for optional, rest and keyword arguments in defining forms @item add reader-macros for very common cases, if needed. @item have the equivalent of compiler-macros so as to define patterns to use when the patterns match a known pattern. E.g. when appending something to a list of known length (before or after), the matching procedure is simple. @item convert everything for use with some kind of first-class environments. @end itemize @node Notes from the code, , To Do List, Design notes @comment node-name, next, previous, up @section Notes from the code Lisp2 style means that instead of writing @example (destructuring-bind (a b (c d ()) . e) foo (bar a b c d e)) @end example You'd write @example (match1 (list* a b (list c d 'nil) e) foo (bar a b c d e)) @end example This might look heavier, but then, the fact that the head of a pattern is a designator for an arbitrary pattern instead of having patterns always be lists except for possible "magic" values like @code{&rest} and other keywords allows patterns to be clearer, and @emph{extensible}. Thus you can trust that any symbol in head position is a pattern name, while any symbol in parameter position is a variable name, except if it is a special symbol, or if the head is a pattern macro, in which case it controls the meaning of the parameters. The only predefined special symbol is @code{_} that matches everything. I used to have @code{T} match anything (top) and @code{NIL} match nothing (bottom), but nobody liked it, so instead they are considered (together with keywords) as literals that match the constants @code{T} and @code{NIL}. Predefined functional patterns are @code{CONS}, @code{LIST}, @code{LIST*}, @code{VECTOR}, that match corresponding objects with a known arity. Predefined macro patterns are @code{QUOTE}, @code{VALUE}, @code{LIKE-WHEN}, @code{AND}, @code{WHEN}, @code{OF-TYPE}, @code{SLOT*}, @code{ACCESSOR*}, that respectively match a literal constant, the value of an expression, a pattern with a guard condition, the conjunction of several patterns, just a guard condition, any value of given type, any object with slots as specified, and object with accessors as specified. In fare-clos, it is also possible to match against an @emph{instance} of a class with slots specified by initargs. @code{IFMATCH} tries to match a pattern with an expression, and conditionally executes either the success form in a properly extended lexical environment, or the failure form in the original lexical environment, depending on whether the match succeeded (with freshly bound variables) or not. @code{MATCH} (that I won't rename to @code{COND-MATCH}) tries to match a given expression with several patterns, and executes the body of the matching clause if found. @code{EMATCH} is like @code{MATCH} except that when no match is found, it raises an error instead of returning @code{NIL}. With this paradigm, matching patterns are thus dual from normal forms. I like to think of all forms as patterns, with some patterns being in "deconstruction position" (left-hand side of a match clause), and other patterns being in "construction position" (right-hand side of a match clause). Although the current implementation follows Erlang (or ML-like) semantics for matching, this paradigm can generalize to non-deterministic settings, where you'd obtain something much like Mercury, unifying functional and logic programming -- however, I haven't even attempted to implement non-determinism (maybe this could be done using Screamer). NB: Actually, I had first thought about this pattern-matcher when I was more of a Lisp1 fan, and the fact that Lisp2 was much more natural for the pattern matcher finished to turn me into a Lisp2 fan. @node Function Index, , Design notes, Top @unnumbered Function Index @c{@printindex cp} @printindex fn @c{@printindex vr} @bye