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

Re: semantics of DEFINE (and nesting)


In article <1030@syma.sussex.ac.uk>, aarons@syma (Aaron Sloman) writes:
>jar@ZOHAR.AI.MIT.EDU (Jonathan Rees) writes:
>> It *was* an explicit decision on the part of the designers, made in
>> 1981.  It was an attempt to have something similar to the MIT Scheme
>> define but without coupling it to the syntax or semantics of lambda.
>> We never properly implemented the feature (LOCALE, for those of you
>> who have seen the T manual) that would have made it coherent, however.
>> Personally, I now would like to see T changed either to implement R3RS
>> define or to allow defines only at "top level" (given a suitable
>> non-global definition of "top level").
>In Pop-11 you can use define locally and it is frequently and very
>effectively used for two main purposes, and less importantly for
>a third:
>(a) Temporarily alter the error handler, standard character
>output consumer, interrupt handler, or other procedures that define
>the current environment, need to be changed in a particular
>procedure, and need to be re-set when that procedure is exitted
>whether normally or abnormally (e.g. via exitto, or by temporarily
>suspending a lightweight process using that procedure - in the
>latter case the temporary value is re-set if the procedure is
>resumed.) Typical example, redefining -interrupt locally-:

Though Scheme has no standard for speaking about interrupt handlers and
presuming that the code that was handling the interrupt dispatch did so using
the current environment (an admittedly complex issue with interrupts), I see no
reason why the standard LET & LETREC could not supply the functionality you are
seeking.  As I understand your comment you wish to have local definitions, as
Scheme believes in first class functions, functions can be introduced any place
that a Scheme object can be introduced.  What is at issue here is the meaning
of the define "command."

>  define foo(...,....);
>    lvars oldinterrupt=interrupt;   ;;; save previous value in local var.
>    define interrupt();
>      pr('Message about being in foo');
>      popready();     ;;; interactive break
>      oldinterrupt(); ;;; if it exits normally do previous interrupt
>    enddefine;
>  ...body of foo...
>  enddefine

(define foo
  (lambda (...)
    (let ((interrupt
	   (lambda ()
	     (newline) (display Message about being in foo)
	     (break)			;!Not standard! push a break loop
	     (interrupt))))		;This reference to interrupt refers to
					;the binding of interrupt outside this
      body of foo)))

Please note that I do not agree that this is the best way to shadow an
interrupt handler, however I am showing how to transliterate the above code

>(b) Define a local procedure that is required ONLY within the
>nesting procedure.

Again, the functionality of LET & LETREC allow this. (e.g.,

;; BLORF alpha beta     [FUNCTION]
;; PURPOSE: Stupid example of how to get notification in a given context.

(define blorf
 (lambda (alpha beta)
  (let ((cons                              ;Define a new cons to give notice
         (lambda (obj-1 obj-2)
          (newline) (display "Cons was called from blorf")
          (cons obj-1 obj-2))))            ;Refer to the cons outside
   (if (eq? alpha beta)
    (cons alpha beta)
    (vector alpha beta)))))

>My suspicion is that people who don't appreciate the usefulness of
>such nested procedure definitions must be people who have not been
>using a language that allows these constructs. Here at Sussex there
>was a gradual conversion among programmers using Pop-11, especially
>after we introduced lexical scoping as an option.

Having the ability to nest functions is, of course, a wonderful thing, but I do
not believe that anyone in the Scheme community contests that.  The questions
related to first class incremental environments, WELL there you will get

>(c) If you simply want to change the global value of a procedure
>identifier you can do things like:
>    define foo ....;
>       define foo_interrupt;
>        ....
>       enddefine;
>        foo_interrupt -> interrupt;     ;;; sets the value outside foo.
>    enddefine;

(define foo
 (lambda (...)
  (let ((foo-interrupt
         (lambda ()

   (set! interrupt foo-interrupt)        ;Sets the value outside foo.


>or to ensure that it is set in all current contexts
>    set_global_valof(foo_interrupt, "interrupt");

I have no idea what this would mean in Scheme, so...

>I would say that a lisp-like language that doesn't allow nested
>procedure definitions with these capabilities was seriously
>impoverished. One can of course achieve similar effects by other
>means, but they are bound to be more clumsy and also by not using
>the syntactic nesting you risk hiding an important relationship,
>and thereby confusing people responsible for maintaining code they
>did not write.

I could not agree more, however Scheme *DOES* allow nested procedure
definitions, that properly capture the environment in which it was created,
passed around, etc.

(peace chance)