chicken-users
[Top][All Lists]
Advanced

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

Re: [Chicken-users] macro systems and chicken (long)


From: Alex Shinn
Subject: Re: [Chicken-users] macro systems and chicken (long)
Date: Thu, 17 Apr 2008 20:58:41 +0900
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.1.50 (darwin)

>>>>> "Alaric" == Alaric Snell-Pym <address@hidden> writes:

    >> "define-record-type" (SRFI-9) should be
    >> sufficient. The problem is that it is not that easy
    >> to construct identifiers in hygienic macros (or it
    >> probably is, I don't know, I haven't thought about it
    >> very much, yet. There are many loose ends in the
    >> moment since so much changes).

    Alaric> It shouldn't be a problem - just (string->symbol
    Alaric> (string-append (symbol->string record-name) "-"
    Alaric> (symbol->string slot-name))) or whatever as
    Alaric> usual and then don't explicitly rename it, I
    Alaric> reckon.

Yes, that works fine, you don't have to give up anything at
all moving from unhygienic macros to hygienic macros.  They
are strictly more powerful.  The case of DEFINE-RECORD
shouldn't even need any special handling.

If you do want to unhygienically build a variable to be
bound in a local scope, then you need to tell the body of
that scope that the new variable is a free name (see the AIF
example).

As for DEFINE-MACRO, whether or not you can keep it depends
on what you consider the semantics of DEFINE-MACRO to be
(and note this is only for backwards compatibility, there's
really no reason to keep using it so long as you have the
ER- or RSC- transformers).  If, as in CL's DEFMACRO, you
intend it to operate on and return normal, READ/WRITEable
sexprs, then all hygiene information does need to be
stripped, and this will cause problems.

An alternate view is that the input to and output from
DEFINE-MACRO can be an arbitrary sexpr, including possible
`identifiers', which may or may not be plain symbols,
depending on the use.  You can map/fold/destructure the
macro body however you want like a normal sexpr, but you
have to stick with with identifier API instead of the symbol
API:

  (identifier? obj)
  (identifier=? env1 id1 env2 id2)
  (identifier->symbol id)

This is what Gauche uses, which is natural because Gauche (I
believe) uses Kohlbecker's original coloring algorithm,
which colors all the symbols on each expansion.  This is
simple but slow.

The third view is the RSC-/ER- transformer version of
DEFINE-MACRO.  The syntactic closures algorithm is faster
than coloring, but has the downside that any arbitrary sexpr
can be wrapped up in a closure.  That means any argument to
a syntactic closures macro may be a "syntax object" (or may
not be, depending on where and how it was expanded).  This
is like with SYNTAX-CASE but less consistent - SYNTAX-CASE
at least has the advantage of *always* making it hard for
you.  So, theoretically, a definition like

  (define-syntax let
    (er-macro-transformer
      (lambda (expr rename compare)
        `((lambda ,(map car (cadr expr)) ,@(cddr expr))
          ,@(map cadr (cadr expr))))))

or equivalently with MATCH destructuring

  (define-syntax let
    (er-macro-transformer
      (lambda (expr rename compare)
        (match expr
         ((let ((var val) ...) body ...)
          `((lambda ,var ,@body)
            ,@val))))))

could fail if the (var val) ... list were passed as a syntax
object.  Though probably this would never happen in
practice.

So what we probably want is a SYNTAX-MATCH analog to MATCH
that can transparently destructure syntax objects... which
is really trivial, but then preserving hygiene is another
issue :(

Anyway, regarding DEFINE-RECORD, I've personally been doing
prototyping in Chicken using that and then automatically
converting to DEFINE-RECORD-TYPE, simply for portability
among other Schemes.  You can run the following elisp
function inside the DEFINE-RECORD form to perform the
expansion.

-- 
Alex

(defun expand-define-record ()
  (interactive)
  (beginning-of-defun)
  (let* ((sexp (sexp-at-point))
         (name (symbol-name (cadr sexp)))
         (pred (intern (concat name "?")))
         (make (intern (concat "make-" name)))
         (fields (cddr sexp)))
    (forward-sexp)
    (insert "\n\n(define-record-type ")
    (insert name)
    (insert "\n  ")
    (insert (with-output-to-string (princ `(,make ,@fields))))
    (insert "\n  ")
    (insert (symbol-name pred))
    (insert "\n  ")
    (mapcar
     #'(lambda (x)
         (insert
          (with-output-to-string
            (princ
             `(,x
               ,(intern (concat name "-" (symbol-name x)))
               ,(intern (concat name "-" (symbol-name x) "-set!"))))))
         (insert "\n  ")) 
     fields)
    (insert ")\n")
    ))




reply via email to

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