This is the mail archive of the guile@sourceware.cygnus.com mailing list for the Guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: SRFI-17


> From: Mikael Djurfeldt <mdj@mdj.nada.kth.se>
> 
> Could some bright people please join Per Bothner and Michael Livshin
> in defending our generalized syntax for `set!' in the discussion about
> SRFI-17.

Sorry, I got tired of crusading sometime between Algol 68 and Ada.

It seemed to me that the discussion fell into two parts
  (1) Way off topic raving.  I don't want to join that.
  (2) Good points.  I know they are good, because I already
      made many of them on this list.  (If I didn't hate
      smiley icons I would put one here.)

The most important of the good points are:
  (1) Delete bogus ideas that are not part of the proposal.
      In particular delete all that talk of lvalues, it has nothing
      to do with the case, and misleads people into thinking you
      are proposing "first class variables".  Also delete the
      "questionable definitions" like (set! (string->symbol x) v).
  (2) Tighten up the spec.  It doesn't make it to answer a
      Scheme Request For Implementation with
        "It is not possible to give a really portable
         implementation, but it should be straight-forwarded
         to modify an implementation as needed", especially
      when an implementation is so easy (modulo efficiency).
  (3) Change the name.  A lot of people who wouldn't mind an
      extension are put off by muddling up standard syntax.

I am not sure what the procedure is for changing the SRFI,
and deleting discussion that no longer applies, but I hope
there is one.  I noticed a patch to the SRFI in the discussion,
but did not seem to have been applied at the time.

Here's my patch.  It is based upon the original SRFI, but
replaces the whole thing.

==========================
SRFI 17A: Setf! Macro

Abstract
--------

Many procedures can be thought of as "getting" a value from an
"object" in such a way that "setting" the value also makes sense.
Cdr is such a "getter" procedure, and set-cdr!  is the corresponding
"setter"; vector-ref and vector-set!  are another pair.

It can be troublesome to remember the name of the setter that
goes with your favorite getter, both because setters are used less
(some large programs _never_ use them), and because the naming
conventions are haphazard by tradition and standard.

Therefore this SRFI proposes a macro that makes the following
possible:

   (setf! (car x) v) == (set-car! x v)
   (setf! (list-ref x n) v) == (set-car! (list-tail x n) val)

In Scheme, locations are not values.  This is as it should
be, and the proposed macro does not change this.

Specification
-------------

(define-syntax setf!
   (syntax-rules()
     ( (setf! (f obj arg ...) value)
       ((setter f) obj value arg ...))))

(define setter
   (letrec ((setter-alist
              (list
                (cons car set-car!)
                (cons cdr set-cdr!)
                (cons caar (lambda(x val) (set-car! (car x) val)))
                (cons cadr (lambda(x val) (set-car! (cdr x) val)))
                (cons cddr (lambda(x val) (set-cdr! (cdr x) val)))
                     ... ; ditto for caddr, cdaar, and the rest of the 28
                (cons vector-ref (lambda (x val n)(vector-set! x n val)))
                (cons string-ref (lambda (x val n)(string-set! x n val)))
                (cons list-ref (lambda (x val n)
                                  (set-car! (list-tail x n) val)))
                (cons substring
                      (lambda(s val start end)
                          (if (= (string-length val) (- end start))
                            (let loop ((k start))
                               (if (< k end)
                                   (begin 
                                     (setf! (string-ref s k)
                                            (string-ref val (- k start)))
                                     (loop (+ k 1)) )))))) ))

             (setter (lambda (f)
                       (let ((p (assq f setter-alist)))
                          (if p (cdr p) (error)))))
             (set-setter! (lambda (x val)
                             (if (assq x setter-alist)
                                 (error)
                                 (set! setter-alist (cons
                                                       (cons x val)
                                                        setter-alist))))) )
      (set-setter! setter set-setter!)
      setter))


We define:
  (setf! (proc arg ...) value)
    as  ((setter proc) value arg ...)
    rather than ((setter proc) arg ... value)
because it works better with procedures that take a variable number of
arguments.  This means that the setter for the function vector-ref is
not really set-vector!, but a similar procedure with the arguments
permuted.

Note that it is an error to do (setf! (setter proc) set-proc!) if the
procedure proc already has a setter, and there is no way to change the
setter-alist without calling (setter setter).  A hypothetically good
compiler might be able to do some constant folding based upon this.
In any case, it goes without saying that an implementation may have a
more efficient way of associating the setter to a getter than an
alist.  An interactive system may provide a way to get rid of the
setter associated with a procedure, perhaps as preparation for
installing a new setter.

Also note that (setf! x 42) is an error.  Set! is not the setter
procedure of any getter, because it is not a procedure at all.  It
certainly is not the setter procedure for some invisible "dereference"
procedure.

-- 
     -- Keith Wright  <kwright@free-comp-shop.com>

Programmer in Chief, Free Computer Shop <http://www.free-comp-shop.com>
         ---  Food, Shelter, Source code.  ---

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]