[plt-scheme] Evaluation in local environment?

From: dsj22 (dsj22 at nau.edu)
Date: Tue Apr 1 01:57:44 EDT 2008

Alright, I don't know why that previous message was sent as HTML, but let's 
try this again, without using Thunderbird.

I'm a student using scheme for a class (at Northern Arizona University), and 
I've run into a roadblock with an assignment. The idea is to create a form of 
objects with simple functions, by creating a local environment with "let" with 
all the instance variables and declaring the object (a lambda function) within 
that environment. The main trick is that, of course, I have to be able to read 
in arbitrary class definitions, as definedI thought I had a very elegant and 
simple solution, which declared the functions within a let at construction and 
then called whichever function was passed. So, if you call (point1 'setx 3), 
all point1 just calls (setx 3) in its local environment (well, it's slightly 
more complicated to allow for overloading with different numbers of arguments) 
- a simple eval call on the list of arguments.

This is where I ran into my problem - eval evaluates in the global 
environment. I can't declare the functions in the global environment, because 
I need to be able to create new instances of each "object" dynamically, and 
the functions can't refer to global variables.

Is there any way to achieve the same effect (passed a symbol, look up the 
symbol and return the function it is attached to) but referring to the 
environment created by a let function?

As an example, this is what is constructed by the "new" function I originally 
created, if I use the definition for a "point" object provided by the 
professor:

(let ((x '2) (y '3))
 (let ((xval x) (yval y))
   (let ((getx-0 (lambda () xval))
         (gety-0 (lambda () yval))
         (display-0
           (lambda () (begin (display "Coords: x=") (display xval) (display ", 
y=") (display yval) (newline))))
         (setx-1 (lambda (newx) (set! xval newx)))
         (polar-0
           (lambda ()
             (let ((radius (sqrt (+ (* xval xval) (* yval yval))))
                   (angle (/ (truncate (* (atan (/ yval xval)) (/ 36000 (* 2 
3.1415)))) 100)))
               (list radius angle))))
         (dist-1
           (lambda (p2)
             (let ((x2 (p2 'getx)) (y2 (p2 'gety))) (sqrt (+ (expt (- x2 xval) 
2) (expt (- y2 yval) 2)))))))
     (lambda msg (eval (cons (methods-append (car msg) (cdr msg) 0) (cdr 
msg)))))))

Methods-append takes the method name and list of arguments, and appends the 
number of arguments to the method name. Of course, the above returns a 
function and if I were to bind that to point1 and call (point1 'getx), all I 
get is an undefined identifier error for getx, since it is not defined 
globally.


I've also constructed an alternative solution, which was much more convoluted, 
which uses a long cond statement, with a check for each (appended) method 
name. However, after remaking the new function, I haven't gotten it working 
yet, but I realized I have no idea how to implement self-referential methods - 
that is, methods in the object being able to call (*this* methodname args). 
This would work naturally in my first solution, since the methods are defined, 
but with the second, the cond statement, the "object" would have to call 
itself. Normally, when I have a function call itself, it's because I'm 
assigning it a label then referring to that label. Since I have to have "new" 
only return a function, per the professor's specification, I can't know the 
label.
If there's no solution to my eval problem, is there a way to have a function 
call itself without any label?

Sorry for the long explanation for what boils down to a simple question, and 
thanks in advance for any help.

- David Johnson



Posted on the users mailing list.