Subject: Re: Barriers to Lisp acceptance - a "survey" question
From: rpw3@rigden.engr.sgi.com (Rob Warnock)
Date: 1999/02/28
Newsgroups: comp.lang.lisp
Message-ID: <7bbdah$9hqgf@fido.engr.sgi.com>
Kent M Pitman  <pitman@world.std.com> wrote:
+---------------
| Scheme has an on-and-off thing about specials.  People keep trying to
| remove them because they are problematic.  My analysis is that this is 
| foolish because they are an artifact of the world and to ignore them is
| to ignore the physics of the world--that some things are dependent on
| world state and not usefully reduced to lexical closures and explicit
| arguments as a matter of practice.  A programming language might as well
| mirror reasonable and anticipatable characteristics of the world, or else
| expect that when people try to simulate them they will do a clumsy job
| that the compiler will fail to understand and will not compile well.
| Dynamic variables and global state are a pratical reflection of an 
| inescapable reality that are there to make programming easier to by not
| making you work so hard to get the behavior you know is there.
+---------------

Most Schemes I've used have "fluid-let" or equivalent, which gets you
*that* style of dynamic usage of globals.  And any Scheme can implement
a "mutable closure" for a slightly different style:

	> (define (make-param remembered-value)
	    (lambda new
	      (if (null? new)
	        remembered-value
	        (set! remembered-value (car new)))))
	> (define foo (make-param 'this))
	> foo
	#<procedure>
	> (foo)
	this
	> (foo 'that)
	> (foo)
	that
	> 

Then (as you noted) you can use dynamic-wind [well, in an R5RS Scheme]
to set/restore the value of the closed-over variable:

	> (let ((old (foo))
		(new 'something-else))
	    (dynamic-wind
	      (lambda () (foo new))
	      (lambda () (display (foo)) (newline))
	      (lambda () (foo old))))
	something-else
	> (foo)
	that
	>

MzScheme formalizes this even further with the notion of a "parameter" type:

	http://www.cs.rice.edu/CS/PLT/packages/doc/mzscheme/node99.htm
	A parameter is a procedure that stores and retrieves the state of
	some value. For example, the "current-output-port" parameter stores
	a port value that is used by display when a specific output port
	is not provided. The current value of a parameter is obtained by
	applying the parameter procedure to zero arguments. The value of
	a parameter is set by applying the parameter procedure to a value.
	[The result of a parameter-setting application is void.] For example,
	(current-output-port) returns the current default output port, while
	(current-output-port p) sets the default output port to "p".

	http://www.cs.rice.edu/CS/PLT/packages/doc/mzscheme/node116.htm
	make-parameter v [guard]) returns a new parameter procedure. The
	value of the parameter is initialized to v in all parameterizations.
	...
	The "parameterize" syntactic form temporarily sets the value of a
	parameter while evaluating a body expression, and then restores
	the parameter value before returning the result of the body. The
	syntax of "parameterize" is: 

	  (parameterize ((parameter value)...) body-expr...) 

	The result of a parameterize expression is the result of the last
	body-expr. During the evaluation of the body-exprs, each parameter
	is set in the current parameterization to the corresponding value.
	Once the body-exprs are evaluated, each parameter is restored to
	its value from before evaluating the parameterize expression. 

[I left out a lot more having to do with "parameterizations", which are
related to MzScheme's system of multiple namespaces & threads.]

So my above example using MzScheme "parameters" would be:

	> (define foo (make-parameter 'this))
	> foo
	#<primitive:parameter-procedure>
	> (foo)
	this
	> (foo 'that)
	> (foo)
	that
	> (parameterize ((foo 'something-else))
	    (display (foo))
	    (newline))
	something-else
	> (foo)
	that
	> 

The main things MzScheme "parameters" give you over hand-crafting the
same thing with a macro around dynamic wind are (1) some error checking
[since a "parameter-procedure" is a different type than plain "procedure"],
and (2) its notion of "parameterizations", which supports having selected
sets of parameters change automatically when you switch between threads
[if you have threads avaiable to worry about, that is].

The somewhat-long-winded point being: I think most of the current active
implementors of Scheme(s) would agree that dynamic variables -- or something
that looks like them [such as the above] -- *are* occasionally "just the
right thing"...


-Rob

-----
Rob Warnock, 8L-855		rpw3@sgi.com
Applied Networking		http://reality.sgi.com/rpw3/
Silicon Graphics, Inc.		Phone: 650-933-1673
2011 N. Shoreline Blvd.		FAX: 650-964-0811
Mountain View, CA  94043	PP-ASEL-IA