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

Re: Update functions in Scheme.

Interestingly, in Oaklisp the interaction between COMPOSE and SETTER
that Bard Bloom desires is easy to obtain in a modular way, due to the
way that settable operations are plugged into the type system:

(define compose (make operation))

(add-method (compose (operation) f g)
  (lambda (z) (f (g z))))

(add-method (compose (settable-operation) f g)
  (let ((fg (make settable-operation)))
    (add-method (fg (object) z) (f (g z)))
    (add-method ((setter fg) (object) z x)
       (set! (f (g z)) x))

[ Lets exhibit modularity by making this work for locatable operation too:

  (add-method (compose (locatable-operation) f g)
    (let ((fg (make locatable-operation)))
      (add-method ((locater fg) (object) z)
        (make-locative (f (g z))))
      fg)) ]


Of course, the problem of getting (DEFINE (FOO X) (BAR X)) to make FOO
just as settable as BAR is not so easily addressed.  The difficulty here
is local variables, so one approach is to get rid of all the variable by
translating everything down to a set of combinators.  For instance,

(define (foo a b) (if a (car b) (car (cdr b))))

would first get curried to

(define foo (lambda (a) (lambda (b) (if a (car b) (car (cdr b)))))),

while we note that (SET! (FOO X Y) Z) gets curried to (SET! ((FOO X) Y) Z).

Some nesting gets removed

(define foo (lambda (a) (lambda (b) (if a (car b) (((compose car) cdr) b))))),

we get rid of B

(define foo (lambda (a) (if a car ((compose car) cdr)))),

and use the combinator which could be defined as follows:

(define %if
  (lambda (f)
    (lambda (g)
      (lambda (test)
	(if test f g)))))

to rewrite FOO to

(define foo (%if car ((compose car) cdr))).

Now, assuming that %IF carries through settableness (which it should do
automatically the way Oaklisp COMPOSE did above), i.e.

(setter ((%if f) g)) <=> ((%if (setter f)) (setter g)),

our side effect attempt

(set! ((foo x) y) z)

gets macroexpanded to

(((setter (foo x)) y) z)

which works.

In order to demonstrate that it works, we can work things through.
Substituting in foo's definition, we have

(((setter ((%if car) ((compose car) cdr))) y) z)

which is the same as

((((%if (setter car)) (setter ((compose car) cdr))) y) z)

which is the same as

((((%if (setter car)) ((compose (setter car)) cdr)) y) z)

which, decurrying and reintroducing some variables, is the same as

((%if (lambda (b) ((setter car) b z))
      (lambda (b) ((setter car) (cdr b) z))
      x) y z)

which is the same as

(if x (set! (car y) z)
      (set! (car (cdr y)) z)).

I find it more than a little perverse to use combinators in an effort to
make side effects more convenient.


Acknowledgments: I would like to thank Peter Lee for his moral support.