[plt-scheme] Pattern matching and srfi-42

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Wed Feb 1 15:55:53 EST 2006

Hi all,

I am writing a "small" tutorial on srfi-42 loops. If you
have any nice examples, please send me a note.

As an appetizer here is the implementation of two new
generators :match and :plt-match which bind loop variables
using the normal match.ss or plt-match.ss syntax.


(define-struct entry (name score ))

(define entries
     (make-entry '("Jens Axel" "Søgaard")  3)
     (make-entry '("Noel"      "Welsh")    7)
     (make-entry '("Anton" "van Straaten") 'disqualified)))

`(ul ,@(list-ec (: e entries)
                 (:match ($ entry (f l) s) e)
                 (not (eq? s 'disqualified))
                 `(li ,f ,s)))

now evaluates to:

(ul (li "Jens Axel" 3) (li "Noel" 7))

I had to tap into the private parts of the pattern matcher.
It would be really nice to have a variables-bound-by-pattern
and a match-set! added to the library. [I couldn't
use match-define, since its expansion were to be inserted
in an expression context - therefore the binding of the
variables and the actual setting were separated].

One more thing: Is it possible to customize the behaviour
of compiled match, when the match fails? Below I wrapped
the matching in a (with-handlers ...), but this penalizes
all cases, not just the non-matching ones.

(require-for-syntax (lib "gen-match.ss" "mzlib" "private")
                     (lib "match-helper.ss" "mzlib" "private")
                     (lib "match-error.ss""mzlib" "private")
                     (lib "convert-pat.ss""mzlib" "private"))

(require (lib "etc.ss")
          (lib "list.ss")
          (lib "match-expander.ss" "mzlib" "private")
          (lib "match-error.ss" "mzlib" "private"))

(define-syntax (:plt-match stx)
   (syntax-case stx ()
     [(:plt-match cc pat expr)
      (identifier? #'pat)
      #'(:let cc pat expr)]
     [(:plt-match cc pat expr)
      (let* ((**match-bound-vars** '())
              (gen-match #'the-expr
                         #'((pat never-used))
                         (lambda (sf bv)
                           (set! **match-bound-vars** bv)
                               #,@(map (lambda (x)
                                         #`(set! #,(car x) #,(cdr x)))
                                       (reverse bv)))))))
        #`(:do cc
               (let ((the-expr expr)
                     (match-found? #t)
                     #,@(map (lambda (x) #`(#,(car x) #f))
                             (reverse **match-bound-vars**)))
                   ([exn:fail? (lambda (exn) (set! match-found? #f))])
               () match-found? (let ()) #f ()))]))

(list-ec (: x '(((1 2) 3) ((4 5) 6)))
          (:plt-match (list (list a b) c)  x)
          (list a b c))

(define-syntax (:match stx)
   (syntax-case stx ()
     [(:match cc pat expr)
      (identifier? #'pat)
      #'(:let cc path expr)]
     [(:match cc pat expr)
      (with-syntax ([new-pat (convert-pat #'pat)])
        #'(:plt-match cc new-pat expr))]))

Remember! Please send srfi-42 examples.

Jens Axel Søgaard

Posted on the users mailing list.