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: Taylan Ulrich Bayırlı/Kammer
Subject: Re: (ice-9 nice-9) module update
Date: Wed, 02 Sep 2015 16:11:35 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux)

Panicz Maciej Godek <address@hidden> writes:

> As a follow-up to the thread
> https://lists.gnu.org/archive/html/guile-devel/2015-06/msg00023.html I
> announce that I made an update to the (ice-9 nice-9) module. It no
> longer re-exports every, any and count, but instead it replaces two
> other bindings:
>
> - define-syntax is now blended with define-syntax-rule, so that if one
> writes
>
> (define-syntax (name . pattern) . substitution)
>
> the effect will be the same as if she wrote
>
> (define-syntax name (syntax-rules () ((name . pattern) .
> substitution)))
>
> I think that there's no need to use "define-syntax-rule".
>
> - let-syntax behaves similarly, i.e.
>
> (let-syntax (((name . pattern) replacement)))
> ....)
>
> transforms to
>
> (let-syntax ((name (syntax-rules () ((name . pattern) replacement)))
> ....)
>
> Any comments and suggestions are appreciated.
>
> Best regards,
> M.

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.

It has one annoyance, which is that syntax transformers are only ever
passed one argument so the ability to use the argument list for
something more interesting is diminished, but I wonder if that's really
a big deal.  I prefer to keep things straightforward and consistent,
even if at the expense of forcing a little more verbosity (as long as
it's just a little).

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.  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."

What do others think?  IMO using 'define-syntax-rule' for the
"syntax-rules with one pattern" special case is fine (and already
established), so I would say it's better to allocate 'define-syntax'
itself to the most generic use-case, like in Racket.

---

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. :-)  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.

---

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

Taylan



reply via email to

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