Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't Scheme support first class environments?

Tags:

scheme

racket

I've been reading through SICP (Structure and Interpration of Computer Programs) and was really excited to discover this wonderful special form: "make-environment", which they demonstrate to use in combination with eval as a way of writing modular code (excerpt from section 4.3 on "packages"):

(define scientific-library
  (make-environment
   ...
   (define (square-root x)
    ...)))

They then demonstrate how it works with

((eval 'square-root scientific-library) 4)

In their example, they then go on to demonstrate exactly the usage that I would want - an elegant, minimalist way of doing the "OO" style in scheme... They "cons" together a "type", which is actually what was returned by the "make-environment" special form (i.e. the vtable), and an arg ("the state")...

I was so excited because this is exactly what I've been looking for as a way to do polymorphic dispatch "by symbol" in Scheme without having to write lots of explicit code or macros.

i.e. I want to create an "object" that has, say, two functions, that I call in different contexts... but I don't want to refer to them by "car" and "cdr", I want to both declare and evaluate them by their symbolic names.

Anyway, when I read this I couldn't wait to get home and try it.

Imagine my disappointment then when I experienced the following in both PLT Scheme and Chez Scheme:

> (make-environment (define x 3))
Error: invalid context for definition (define x 3).
> (make-environment)
Error: variable make-environment is not bound.

What happened to "make-environment" as referenced in SICP? It all seemed so elegant, and exactly what I want, yet it doesn't seem to be supported in any modern Scheme interpreters?

What's the rationale? Is it simply that "make-environment" has a different name?

More information found later

I took at look at the online version:

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-28.html#%_sec_4.3

I was reading was the first edition of SICP. The second edition appears to have replaced the discussion on packages with a section on non-deterministic programming and the "amp" operator.

like image 258
Paul Hollingsworth Avatar asked Mar 06 '09 00:03

Paul Hollingsworth


1 Answers

After more digging around I discovered this informative thread on newsnet:

"The R5RS EVAL and environment specifiers are a compromise between those who profoundly dislike first-class environments and want a restricted EVAL, and those who can not accept/understand EVAL without a second argument that is an environment."

Also, found this "work-around":

(define-syntax make-environment 
  (syntax-rules () 
    ((_ definition ...) 
     (let ((environment (scheme-report-environment 5))) 
       (eval '(begin definition 
                     ...) 
             environment) 
       environment)))) 


(define arctic 
  (make-environment 
    (define animal 'polarbaer))) 

(taken from this)

However, I ended up adopting a "message passing" style kinda of like the first guy suggested - I return an alist of functions, and have a generic "send" method for invoking a particular function by name... i.e something like this

(define multiply
  (list
    (cons 'differentiate (...))
    (cons 'evaluate (lambda (args) (apply * args)))))

(define lookup
  (lambda (name dict)
    (cdr (assoc name dict))))

; Lookup the method on the object and invoke it
(define send
  (lambda (method arg args)
    ((lookup method arg) args)))

((send 'evaluate multiply) args)

I've been reading further and am aware that there's all of CLOS if I really wanted to adopt a fully OO style - but I think even above is somewhat overkill.

like image 105
Paul Hollingsworth Avatar answered Sep 22 '22 15:09

Paul Hollingsworth