[Openmcl-devel] matching patterns

Taoufik Dachraoui dachraoui.taoufik at gmail.com
Wed Oct 3 09:00:56 PDT 2012


Hi

I wrote a matching pattern (recursive) function and would like to share it;
it is still work in progress (some bugs are expected to show up anytime)


I started with the destruc function found in onLisp book by Paul Graham.



The following is a draft of a poor doc and some examples of usage:

; variables: untyped :x, typed (:var x (integer 0 9))



keywords :var :all :lone, :some, :not, :or, :and, :type, :match, this



pattern == _ | (:all pattern) | (:lone pattern) | (:not pattern)

             | (:some pattern pattern) | (:var var pattern) | keyword

             | (:or pattern pattern) | (:type primitive-pattern)

             | literal | ( pattern* ) | this | (:match pattern)

     where _ matches anything (any lisp element)

     this is a recursive reference to the current matching pattern

     :match starts a new matching pattern for the current element

     keyword is a variable (ie. :x is equivalent to (:var x _))

  primitive-pattern == lisp types (eg. integer, number, consp, ...)

  literal == lisp atoms (number, string, symbol, ...)



       :x == (:var x _)

       _ == (:type t)

       (pattern1 (:lone pattern2) pattern3) == (:or (pattern1 pattern2
pattern3) (pattern1 pattern3))
       (:some pattern (:type null)) == (:all pattern)

       (match '(1 2 3 . 4) ((:all (:type integer)) 'ok)) -> NIL   fails
because of the dotted list
               :all matches a sequence (:some can match any list as shown
below)
       (match '(1 2 3 . 4) ((:some (:type integer) (:var x (:type
integer))) x)) -> 4
       (match '(1 2 A . 4) ((:some (:type integer) (:var x _)) x)) -> (X .
4)
       (match '(a b c) (('a (:lone 'b) 'c) 'ok))          -> OK

       (match '(a c) (('a (:lone 'b) 'c) 'ok))          -> OK

       (match 3 ((:not (:type integer)) 'ok)) ; match a non integer

         -> NIL

       (:not (_ . _)) == (:not (:type consp)) ; match an atom

       (match '(1 2 3 4) ((:all (:type integer)) 'ok))           -> OK

       (match '((a 1) (b foo) (c ok)) ((:all (:var val ((:var key (:type
symbol)) _))) (list val key)))
          -> ((C OK) C)

       (match '((a 1) (b 2) (c 3)) ((:all ((:var x (:type symbol)) (:var y
(:type integer)))) (list x y)))
         -> (C 3)

       ? (match '(1 (2 2 2) 3) ((:x (:var y (:match (:or (:type null) (2 .
this)))) :z) (values x y z)))
1

(2 2 2)

3

****  (:some _) is problematic (implement rollback?)

      currently we have (:some _) == (:all _)

      *** in general in ((:some p1) p2), p1 and p2 must be incompatible

          that is if x is matched by p2 then x must not be matched by p1



? (defun member? (x e) (match e ((:or (:var r (x . _)) (_ . this)) r)))

MEMBER?

? (member? 'x '(a b x c))

(X C)

? (member? 'x '(a b c))

NIL

? (member? '(1 2) '(a (1 2) b))
((1 2) B)


20120729: TODO convert a regular expression to a pattern

    "a*" -> (:lone ((:all #\a)))

    "a*b" -> ((:lone (:some #\a)) #\b)

  many difficulties are to expect (eg. ".*H" -> ((:some _) #\H)

    some consumes all characters and the match fail because of end of
inputs and we still have #\H to read


I am currently using the match macro to implement a simple lambda calculs
interpreter (normal order, lazy, untyped)

For example the full beta reduction is as follows:

(defun fv? (e u)
  "(member u (fv e))"
  (match e
         ((:var v (:type atom))
          (eq u v))
         (('fn :v :e0)
          (and (not (eq u v)) (fv? e0 u)))
         ((:e0 :e1)
          (or (fv? e0 u) (fv? e1 u)))
         (_ (error "fv?: invalid syntax"))))

(defun br  (eb v ea &optional (i 0))
  "beta-reduction (in-place version)"
  (format t "~Abr: ~S ~S ~S~%" (%cars i) eb v ea)
  (let ((r
  (match eb
         (v ea)
         ((:or (:type atom) ('fn v _)) eb)
         (('fn :u :e0)
          (if (not (and (fv? ea u) (fv? eb v)))
              (progn
                (setf (third eb) (br e0 v ea (1+ i)))
                eb)
              (let ((w (gensym)))
                (setf (third eb) (br (br e0 u w (1+ i)) v ea (1+ i)))
                (setf (second eb) w)
                eb)))
         ((:e0 :e1)
          (setf (first eb) (br e0 v ea (1+ i)))
          (setf (second eb) (br e1 v ea (1+ i)))
          eb)
         (_ (error "br: invalid syntax")))))
    (format t "~Arbr r:~A~%" (%cars i) r)
    r))


Kind regards
Taoufik
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.clozure.com/pipermail/openmcl-devel/attachments/20121003/86ea03a0/attachment.htm>


More information about the Openmcl-devel mailing list