[plt-scheme] Re: match-let bug or feature?
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.
>