guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: (ice-9 nice-9) module update


From: Panicz Maciej Godek
Subject: Re: (ice-9 nice-9) module update
Date: Wed, 2 Sep 2015 17:06:31 +0200


2015-09-02 16:11 GMT+02:00 Taylan Ulrich Bayırlı/Kammer <address@hidden>:

Maybe it would be good to make define and define-syntax more symmetric.
So if

    (define (foo . rest) . body)

is equivalent to

    (define foo (lambda rest . body)),

then

    (define-syntax (foo . rest) . body)

should perhaps be equivalent to

    (define-syntax (lambda rest . body)).

This is how Racket does it too, and one could say it's the most logical
and generalized choice.


That was my first guess, too, and so initially I did that the way you described, but I eventually concluded that mapping

(define-syntax (s . args) . body)

as

(define-syntax s (syntax-rules () ((s . args) . body)))

is more analogous to mapping

(define (s . args) . body)

as

(define s (lambda args . body))

than (define-syntax s (lambda args . template))

This is because, at least in the substitutional model of computation, in both define/lambda and define-syntax/syntax-rules case you can substitute (s values ...) with body where the occurences of args in body are replaced with values. Interpreting (define-syntax (s . args) . body) as (define-syntax s (lambda args . body)) does not work that way, because, as you noted, syntax transformers can take only a single argument, and -- more importantly -- the argument doesn't say anything about how the macro is intended to be used (it is, as Guile manual puts it, "a leaky implementation detail").

I think that syntax-case or syntax-rules with many clauses resembles the use of case-lambda more.

Also, while it has that annoyance, it also has the advantage of allowing
you to do anything you want with that one syntax-object argument you
receive, e.g. passing it to syntax-case or (in the future) syntax-parse.
OTOH, making the argument list "special" will tie the form to a specific
macro system like syntax-rules or syntax-case, and also forbid using
multiple pattern/template pairs on it.

Not forbid. This is just an extension of syntax that would otherwise be illegal.
I agree that it is dubious that the interpretation ties itself to one macro system, but this is the most commonly used macro system in Scheme. I agree that there's an important difference between define-syntax+syntax-rules and define+lambda -- namely, that the former has no intrinsic conditional like "if".

  In my experience, using multiple
patterns is very common, and some code-bases also make heavy use of
syntax-case instead of syntax-rules, so I wouldn't allocate a primary
"syntax slot" like '(define-syntax (...) ...)' to something very
specific like "syntax-rules with one arm."


In my experience it is also very common, but interpreting (define-syntax (name . args) ...) as (define-syntax name (lambda args ...)) doesn't improve readability, and moreover might lead to confusion.

(define-syntax s (lambda (stx) (syntax-case stx () ...)))

is more explicit than

(define-syntax (s stx) (syntax-case stx () ...))

and the former should definitely be preferred over the latter, which would only bring confusion and no improvement whatsoever


There are many possible extensions to 'let' (abbrev. for lambda, for
let-values, or for match-let), all of which make equally much sense to
me, so I think they're all bad, because no matter which one you
sanction, you will have discriminated against two others. :-)

Well, no, actually there are only two reasonable extensions -- let-values and match-let go together well, so the only one that can be discriminated is the lambda (which would actually discriminate the perfectly-reasonable srfi-71 let variant). And while I don't like the discrepancy between pattern-matching let and syntax-ruling let-syntax, I don't think that interpreting (let (((f x) '(1 2))) ...) as (let ((f (lambda (x) '(1 2)))) ...) could actually be useful. But I do admit that it is only my personal taste&experience. (I actually prefer to introduce internal function definitions using the "define" form)

  Just keep
pure 'let' pure, and let people specify the exact variant they want...

However, for 'let-syntax' the situation is different.  There is no
let-syntax-values, and there is no match-let-syntax.  There is only one
way to use let-syntax, which is to bind the identifier to a syntax
transformer.  So I agree it's a good idea to extend it in that
direction.

That leaves the question of what sort of syntax transformer should be
created, syntax-rules or syntax-case or lambda, and the obvious choice
to me is to make it consistent with define-syntax, so in line with my
other recommendation, I would make

    (let-syntax (((foo stx) ...)) ...)

equivalent to

    (let-syntax ((foo (lambda (stx) ...))) ...).

And so the widest possible use-cases are covered.

Admittedly that slightly discriminates against syntax-rules, which
doesn't go well with the implicit lambda.  For that reason I would
propose a different syntax, similar to define-syntax-rule:

(let-syntax-rule
    (((foo x y)
      (do stuff))
     ((bar a b)
      (do stuff)))
  (body goes here))

This way everything is very consistent.  Define-syntax and let-syntax
are maximally generic and assume no specific macro system so one can
dispatch to the system of choice, the exception being syntax-rules which
requires there *not* to be a lambda, so for syntax-rules we define the
*-syntax-rule variants, and hopefully everyone is happy.

---

I also pondered on the following two, but note that each save merely a
single trivial line of code per syntax-rules invocation, so I think they
have little merit:

(define-syntax-rules foo ()
  ((_ x y)
   (do stuff))
  ((_ x y z)
   (do other stuff)))

(let-syntax-rules
    ((foo ()
      ((_ x y)
       (do stuff))
      ((_ x y z)
       (do other stuff)))
     (bar ()
      ((_ a b)
       (do stuff))
      ((_ a b c)
       (do other stuff))))
  (body goes here))

They're highly consistent with the rest though, so it shouldn't hurt
adding them if others think it's worth it.

Well, the define-syntax-rules and let-syntax-rules are non-controversial, and I could even say that I like them a lot (especially let-syntax-rules).
My point, however, is to make things controversial, and to pick the right interpretation for the formsthat otherwise wouldn't be legal.

So I think that it would be awesome to map

(let-syntax ((name keywords pattern . patterns))
   body)

to

(let-syntax ((name (syntax-rules keywords pattern . patterns)))
  body)

(and so forth)
 

That amounts to 6 cents, I hope it wasn't excessive. :-P

I only have a dollar: $


reply via email to

[Prev in Thread] Current Thread [Next in Thread]