[plt-scheme] About matching ors...

From: Danny Yoo (dyoo at hkn.eecs.berkeley.edu)
Date: Fri Feb 17 19:15:20 EST 2006


> When requiring plt-match.ss and trying:
> (define test
>     (match-lambda
>       [(list (or id
>                  (list x y z)))
>        (printf "~a ~a ~a ~a ~n" id x  y z)]
>       [_
>        (printf "buh~n")]))
>
> I get:
> expand: unbound variable in module in: x

Hello!


The matcher appears to be based on Andrew Wright's matcher.  According to:

http://www.cs.rice.edu/CS/PLT/packages/doc/match/node3.htm#SECTION00021000000000000000

all subpatterns should bind the same set of pattern variables.  So
something like:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module test mzscheme
  (require (lib "plt-match.ss"))
  (provide (all-defined))
  (define first&last
    (match-lambda
     [(or (list x y)
          (list x _ y)
          (list x _ _ y)
          (list x _ _ _ y))
      (list x y)])))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


will work, but something like:

;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (define first&last-broken
    (match-lambda
     [(or (list a b)
          (list a b c)
          (list a b c d)
          (list a b c d e))
      (list a e)]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;

won't.


That being said, it looks like the restriction is a little weaker, since:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define first&last
    (match-lambda
     [(or (list first last)
          (list first b last)
          (list first b c last)
          (list first b c d last))
      (list first last)]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

appears to work fine.  So I think it's just that the consequent has to
make sense regardless of which 'or' pattern is taken.  In your example:

>       [(list (or id
>                  (list x y z)))
>        (printf "~a ~a ~a ~a ~n" id x  y z)]

what value should x, y, or z take if 'id' is what matches?  This feels
like it really wants to be two patterns rather than one.


If we really wanted to combine them together, we could do something like
this:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define test
  (match-lambda
   [(list (or (and id (app void x) (app void y) (app void z))
              (and (list x y z) (app void id))))
    (printf "~a ~a ~a ~a ~n" id x  y z)]
   [_
    (printf "buh~n")]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

in which we say that if the first case matches, the other variables are
explicitely voided out:

;;;;;;
> (test '(hello))
hello #<void> #<void> #<void>
> (test '(hello world testing))
buh
> (test '((hello world testing)))
(hello world testing) #<void> #<void> #<void>
;;;;;;

but I have a hard time reading the above pattern.  *grin*




> Another question:
> (define parse
>     (match-lambda
>         [(list (or 'x 'y 'z) a ...)
>          <<<<<<<<<<<<<<<<< How can know which of the first elements
> matched (x, y, or z)?
>         )))
>
> My solution is usually to drop the match-lambda, use match, add an
> argument and then check the car of the argument to see which one
> matched but is there a better way?


Do you have to do something different based on what the first element is?
If so, why not make three separate clauses?

;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define parse
  (match-lambda
    [(list 'x a ...) ...]
    [(list 'y a ...) ...]
    [(list 'z a ...) ...]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;


Best of wishes!



Posted on the users mailing list.