Email list hosting service & mailing list manager

Re: Lexical scope of pattern variables is not strictly respected in the sample implementation Marc Nieper-Wißkirchen (03 Sep 2020 10:09 UTC)

Re: Lexical scope of pattern variables is not strictly respected in the sample implementation Marc Nieper-Wißkirchen 03 Sep 2020 10:09 UTC

Another reason came to my mind why the original Wright semantics
(pattern variables are bound in the lexical scope of each body; the
one specified in the SRFI but not the one implemented) is the "right
one".

Consider the following example of a new keyword let-list, whose syntax is

(let-list (<list-binding> ...) <body>)

where <list-binding> is of the form ((<identifier> ...) <init>). When
evaluating, a let-list form, <init> is supposed to evaluate to a list
of exactly as many elements as there are <identifier>s, which are
bound and in whose locations the list elements are stored.

This is the first attempt to write let-list:

(define-syntax let-list
  (syntax-rules ()
    ((let-list (((x ...) init) ...) body1 body2 ...)
     (match-let (((x ...) init) ...) body1 body2 ...))))

Obviously, this is only almost correct as the example

(let-list (((x _) (list 1 2))) _)

shows, which should evaluate to 2. The problem with the above
definition of let-list is that match-let considers some identifiers to
be special, which let-list shouldn't.

To solve this problem with the current specification of Wright, we
have to create temporary identifiers in let-list, use them in the
macro use of match-let and bind the original identifiers to the
temporary ones in the body.

It would be easier if the match macro had a way to use arbitrary
identifiers. The Racket match has; the pattern there is (var
<identifier>), which is equivalent to <identifier> but does not
interpret <identifier> as one of the special ones. I have already
proposed to add this pattern to the Wright matcher (because it does
not make less sense with the Wright matcher than with Racket's). So
let us assume that we have an extension (or some later draft) of SRFI
204 that allows var-patterns. Then we can code:

(define-syntax let-list
  (syntax-rules ()
    ((let-list (((x ...) init) ...) body1 body2 ...)
     (match-let ((((var x) ...) init) ...) body1 body2 ...))))

Now, (let-list (((x _) (list 1 2))) _) will evaluate to 2 as expected.

The idyllic world, however, would be destroyed by the eager binding of
pattern variables as the implementation currently does:

(let-list (((var x) (list 1 2))) x)

should likewise evaluate to 2, but with eager binding, the symbol var
would lose its special status after it has been bound to 1 so that 2
would be matched against the list (1 x), which will fail, of course.

We see that we get much more satisfactory results (and semantics) with
binding in the body. We don't want the need to add a warning not to
use the match macro in other macros that process input from the
outside.

Marc

Am Mi., 2. Sept. 2020 um 07:47 Uhr schrieb Marc Nieper-Wißkirchen
<xxxxxx@nieper-wisskirchen.de>:
>
> Am Mi., 2. Sept. 2020 um 00:08 Uhr schrieb Alex Shinn <xxxxxx@gmail.com>:
> >
> > On Tue, Sep 1, 2020 at 11:08 PM Marc Nieper-Wißkirchen <xxxxxx@nieper-wisskirchen.de> wrote:
> >>
> >>
> >> (1) We lose compatibility with the original Wright matcher and other
> >> descendants like Racket's.
> >
> >
> > We've already broken compatibility with Wright in unlikely cases by
> > adding new matching rules (***, *.., =..).  This is I think also an unlikely
> > case in practice and so the decision should be what is more useful in
> > practice.
> >
> > The Racket matcher already differs wildly in almost all cases (except
> > when the entire pattern is quasiquoted), so any compatibility there is
> > pretty meaningless.
>
> Both true for concrete macros that use extensions of either matcher.
> But while there are differences in the details, the overall semantics
> (and the mental model) have been compatible so far.
>
> >> (2) The Wright matcher has clear semantics. The semantics currently
> >> implemented by your match is hardly that clear. For example, in a list
> >> pattern that contains a predicate, the pattern variables on the left
> >> will be available, but not those on the right.
> >
> >
> > Yes, it would have to be specified as a letrec*-style semantics.
> >
> >>
> >> (3) The proposed new semantics is complicated even more by the
> >> presence of ellipsis patterns.
> >
> >
> > That is a little weird but could be specified.
>
> And you have to add another exception for "not" patterns.
>
> > Anyway, I'm not arguing for this, I was just stating my preference.
> > I won't be the one writing the spec or fix either way :)
>
> One day I may find time to write match.
>
> Marc