Newsgroups: comp.lang.scheme
Path: cantaloupe.srv.cs.cmu.edu!rochester!cornellcs!newsstand.cit.cornell.edu!portc01.blue.aol.com!news-peer.gsl.net!news.gsl.net!howland.erols.net!www.nntp.primenet.com!nntp.primenet.com!arclight.uoregon.edu!netnews.worldnet.att.net!uunet!in3.uu.net!world!wware
From: wware@world.std.com (Will Ware)
Subject: Re: Internal defines (was Re: How to do this in Scheme (elegantly)?)
Message-ID: <DyzK5L.D8y@world.std.com>
Organization: The World Public Access UNIX, Brookline, MA
X-Newsreader: TIN [version 1.2 PL2]
References: <LOU.96Oct3181435@fubar.cs.montana.edu> <3255326D.112D@ontos.com> <ttnsp7pphg7.fsf@wagner.nexen.com>
Date: Wed, 9 Oct 1996 01:58:32 GMT
Lines: 66

Tom Lyons (tbl@nexen.com) wrote:
: Is it crazy or wrongheaded to hope that were Scheme to get a standard
: module system, DEFINE might introduce bindings in some module scope
: like the exportable environment of the current structure?  That would
: make

:     (let ((stack '()))
:         (define (push thing) (set! stack (cons thing stack)))
:         (define (pop) (set! stack (cdr stack)))
:         ...)

[ behave as expected, with "stack" a shared, hidden variable ]

It would be neat to be able to do this in Scheme. In Common Lisp, you
can write it exactly as you wrote it above, and the define's (actually
defun's) are seen by the outer environment.

There is a hack you can do, however, like this (stolen from SICP):

(define (make-stack)
  (let* ((stack '())
	 (push (lambda (thing)
		 (set! stack (cons thing stack))))
	 (pop (lambda ()
		(let ((x (car stack)))
		  (set! stack (cdr stack))
		  x)))
	 (dispatcher (lambda (what . args)
		       (cond ((eq? what 'push) (push (car args)))
			     (else (pop))))))
    dispatcher))

"make-stack" returns a function (an anonymous copy of "dispatcher")
with an associated private variable (stack). Actually. you'd want
"pop" to check for an empty stack. Anyway, to use it, do this:

(define my-stack (make-stack))

(my-stack 'push 1)
(my-stack 'push 2)
(my-stack 'push 3)

(my-stack 'pop) ==> 3
(my-stack 'pop) ==> 2
(my-stack 'pop) ==> 1

This embodies the idea that the hidden variable wants to be limited to
only one object (my-stack). It's that whole object-oriented thing
people get excited about. And if you wanted to, you could do this, at
the risk of being a little less pretty:

(define my-stack (make-stack))
(define (push thing) (my-stack 'push thing))
(define (pop) (my-stack 'pop))

But now you have "my-stack" floating around the top-level environment,
which is really no improvement over leaving the stack itself floating
around. Maybe there's a way to un-define "my-stack" after you finish
defining "push" and "pop". If so, you'd be able to do the same thing
with a globally-defined stack variable.

Interesting question.
-- 
-------------------------------------------------------------
Will Ware <wware@world.std.com> web <http://world.std.com/~wware/>
PGP fingerprint   45A8 722C D149 10CC   F0CF 48FB 93BF 7289
