[plt-scheme] Re: match-let bug or feature?

From: Derick Eddington (derick.eddington at gmail.com)
Date: Fri Jan 4 23:50:45 EST 2008

A solution is to evaluate the expressions first and then pass the
resultant values to a nested series of `match' expressions.  This keeps
the patterns separated so that if they have duplicate variable names
they are not in a concatenated pattern which `match' will interpret
according to its duplicate identifier feature, and it puts the
`match-let' body inside the scope of all the bound pattern variables.
However, because of the nested `match' expressions, a pattern variable
binding with the same name as a previous `match-let' [pat expr] clause's
binding will shadow the previous binding (the `expr's are still
evaluated according to let semantics); there doesn't seem to be any
other way of keeping the body inside the scope of all the bindings; a
complete solution would detect duplicate variable names in all the
patterns, while still allowing the duplicate names feature within an
individual pattern, by doing some tricky magic of inspecting the
`match-let' patterns.

I'll paste below my code (R6RS) which implements the partial solution I
described above.  Comments welcome.

(define-syntax nest-matching
  (lambda (stx)
    (syntax-case stx ()
      [(kw ctxt () body0 body* ...)
       #'(begin body0 body* ...)]
      [(kw ctxt ([pat0 expr0] [pat* expr*] ...) body0 body* ...)
       #'(match/lexical-context ctxt expr0
           [pat0 (kw ctxt ([pat* expr*] ...) body0 body* ...)])])))
  
(define-syntax match-let/lexical-context
  (lambda (stx)
    (syntax-case stx ()
      [(_ ctxt named () body0 body* ...)
       (and (identifier? #'ctxt) (identifier? #'named))
       #'(let named () body0 body* ...)]
      [(_ ctxt () body0 body* ...)
       (identifier? #'ctxt)
       #'(begin body0 body* ...)]
      [(_ ctxt named ([pat* expr*] ...) body0 body* ...)
       (and (identifier? #'ctxt) (identifier? #'named))
       (with-syntax ([(t* ...) (generate-temporaries #'(pat* ...))])
         #'(letrec ([named (lambda (t* ...) 
                             (nest-matching ctxt ([pat* t*] ...) body0 body* ...))])
             (named expr* ...)))]
      [(_ ctxt ([pat* expr*] ...) body0 body* ...)
       (identifier? #'ctxt)
       (with-syntax ([(t* ...) (generate-temporaries #'(pat* ...))])
         #'(let ([t* expr*] ...)
             (nest-matching ctxt ([pat* t*] ...) body0 body* ...)))])))
  
(define-syntax match-let
  (lambda (stx)
    (syntax-case stx ()
      [(_ named () body0 body* ...)
       (identifier? #'named)
       #'(let named () body0 body* ...)]
      [(_ () body0 body* ...)
       #'(begin body0 body* ...)]
      [(ctxt named ([pat* expr*] ...) body0 body* ...)
       (identifier? #'named)
       #'(match-let/lexical-context ctxt named ([pat* expr*] ...) body0 body* ...)]
      [(ctxt ([pat* expr*] ...) body0 body* ...)
       #'(match-let/lexical-context ctxt ([pat* expr*] ...) body0 body* ...)])))

-- 
: Derick
----------------------------------------------------------------

On Fri, 2008-01-04 at 12:51 -0800, Derick Eddington wrote:
> Welcome to MzScheme v3.99.0.8 [3m], Copyright (c) 2004-2008 PLT Scheme Inc.
> > (require (lib "match.ss"))
> > (match-let ([(a b) (list 1 2)]
>               [(b a) (list 2 1)])
>     (list a b))
> (1 2)
> > (match-let ([(a b) (list 1 2)]
>               [(b a) (list 3 1)])
>     (list a b))
> match: no matching clause for ((1 2) (3 1))
> 
>  === context ===
> /home/d/plt/collects/mzlib/private/match/match-error.ss:9:4: match:error
> /home/d/plt/collects/scheme/private/misc.ss:63:7
> 
> 
> I'm leaning towards "bug" because for a normal `let' you can't have
> duplicate identifiers, and the scope of the duplicate identifier feature
> of match patterns is restricted to individual match clauses.  Though, I
> can see how the way it is now could have interesting uses.
> 




Posted on the users mailing list.