Am Mi., 1. Apr. 2020 um 15:07 Uhr schrieb John Cowan <xxxxxx@ccil.org>:
Thanks! I hoped to flush out something like this, O Master of Macrology.

I am just an intermediate among true masters like Al Petrovsky and Oleg Kiselyov.


I'm going to submit these and Chicken's explicit renaming version to SRFI 2 as contributed implementations.

On Wed, Apr 1, 2020 at 2:49 AM Marc Nieper-Wißkirchen <xxxxxx@nieper-wisskirchen.de> wrote:
Am Mi., 1. Apr. 2020 um 04:10 Uhr schrieb John Cowan <xxxxxx@ccil.org>:
I may add maybe-cond later.

I will not be adding maybe-and-let*, because there is no portable implementation of and-let* (there is one for define-macro, one for explicit renaming, and one for syntax-case).

What do I miss? and-let* can easily be implemented in R7RS-small.

The following is a faithful implementation with `syntax-case' (the only thing it doesn't check — and doesn't have to — is that the bound variables are disjoint, which is most likely an error in SRFI 2 anyway and should be fixed there because wrong assumptions about let* were made there):

(define-syntax and-let*
  (lambda (stx)
    (syntax-case stx ()
      ((_ ())
       #'#t)
      ((and-let () form form* ...)
       #'(begin form form* ...))
      ((_ ((id expr)))
       #'expr)
      ((_ ((expr)))
       #'expr)
      ((_ (id))
       (identifier? #'id)
       #'id)
      ((_ ((id expr) . claw*) . body)
       #'(let ((id expr))
       (and id (and-let* claw* . body))))
      ((_ ((expr) . claw*) . body)
       #'(and expr (and-let* claw* . body)))
      ((_ (id . claw*) . body)
       (identifier? #'id)
       #'(and id (and-let* claw* . body)))
      ((_ (claw . claw*) . body)
       (error "invalid and-let* claw" #'claw))
      (_
       (error "ill-formed and-let* form" stx)))))

A rewrite using `syntax-rules' that still uses the fenders of `syntax-case' is, therefore:

(define-syntax and-let*
  (syntax-rules ()
    ((_ ())
     #t)
    ((and-let () form form* ...)
     (begin form form* ...))
    ((_ ((id expr)))
     expr)
    ((_ ((expr)))
     expr)
    ((_ (id))
     (identifier? #'id)
     id)
    ((_ ((id expr) . claw*) . body)
     (let ((id expr))
       (and id (and-let* claw* . body))))
    ((_ ((expr) . claw*) . body)
     (and expr (and-let* claw* . body)))
    ((_ (id . claw*) . body)
     (identifier? #'id)
     (and id (and-let* claw* . body)))
    ((_ (claw . claw*) . body)
     (syntax-error "invalid and-let* claw"))
    ((_ . _)
     (syntax-error "ill-formed and-let* form")))))

To get a fully portable implementation, just drop the fenders:

(define-syntax and-let*
  (syntax-rules ()
    ((_ ())
     #t)
    ((and-let () form form* ...)
     (begin form form* ...))
    ((_ ((id expr)))
     expr)
    ((_ ((expr)))
     expr)
    ((_ (id))
     id)
    ((_ ((id expr) . claw*) . body)
     (let ((id expr))
       (and id (and-let* claw* . body))))
    ((_ ((expr) . claw*) . body)
     (and expr (and-let* claw* . body)))
    ((_ (id . claw*) . body)
     (and id (and-let* claw* . body)))
    ((_ . _)
     (syntax-error "ill-formed and-let* form")))))

This version will accept a few invalid uses of `and-let*' but doesn't change the meaning of valid programs, so it is a faithful implementation of `and-let*' as well. If you want to signal invalid uses, you can do this with a bit more effort by using a helper macro like `em-symbol?' ([1]) that portably checks whether a macro argument is an identifier or not.

Marc