Sujet : Re: History of lexical scope in Lisp
De : jbb (at) *nospam* notatt.com (Jeff Barnett)
Groupes : comp.lang.lispDate : 17. Mar 2024, 07:13:20
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <ut5u5i$3c0e6$1@dont-email.me>
References : 1 2 3 4 5
User-Agent : Mozilla Thunderbird
On 3/16/2024 1:27 AM, Lawrence D'Oliveiro wrote:
On Sat, 16 Mar 2024 00:46:21 -0600, Jeff Barnett wrote:
First off, I believe that many if not most exception-related primitives
expand in terms of dynamic variables.
Consider the following Python example:
class MyException1(Exception) :
pass
#end MyException1
class MyException2(Exception) :
pass
#end MyException2
def func1() :
raise MyException1
#end func1
def func2() :
raise MyException2
#end func2
def func3() :
class MyException1(Exception) :
pass
#end MyException1
try :
func1()
except MyException1 :
# will never get here
print("caught MyException1 in func3")
#end try
#end func3
def func4() :
try :
func2()
except MyException2 :
print("caught MyException2 in func4")
#end try
#end func4
for f in (func1, func2, func3, func4) :
try :
print("* call %s" % f.__name__)
f()
except MyException1 :
print("caught MyException1 at top level")
except MyException2 :
print("caught MyException2 at top level")
#end try
#end for
Here is the output it produces:
* call func1
caught MyException1 at top level
* call func2
caught MyException2 at top level
* call func3
caught MyException1 at top level
* call func4
caught MyException2 in func4
func4 shows how the search for a handler is based on dynamic execution
nesting. func3 shows how exception matching is based on lexical
scoping.
Unfortunately, I don't speak Python. However if your point is that you can build "simulations" of one sort of scoping out of primitives for another sort, I agree.
In fact Doug Pintar and I invented and used a language called CRISP (
https://www.softwarepreservation.org/projects/LISP/crisp_ibm370_sdc) in the 1070s. It was used to implement some interesting speech understanding systems as part of the DARPA SUR Program. CRISP Allowed local and dynamic bindings and stack segments including bindings, catches, and return points where represented. There where primitives that allowed these stack segments to be elements of three types of trees: binding trees where dynamic bindings not located in one segment where sought in the parent segment; resume trees where segment executions did a return that was not handled in the current segment were reflected to the parent segment; and handler trees where a throw not handled by the executing segment was continued into the parent segment. The "highest" node in all trees was the global context. The parent-child relation in all trees could be rearranged under program control. Out of the related primitives, e.g., eval-in(exp, segment) you could construct pretty much whatever binding, control. and error handling structure that you needed. The reason for this baroque approach is that when we started constructing speech systems we had absolutely no idea what program organization structures would be convenient.
The above was inspired by some papers using the rubric "spaghetti stacks". Don't remember the authors but Danny Bobrow might have been implicated.
-- Jeff Barnett