[plt-scheme] Evaluation in local environment?

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Tue Apr 1 03:28:43 EDT 2008

dsj22 wrote:
> 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?

You cannot use 'eval' that way in PLT Scheme. Nor should you, even if it 
were possible.

More importantly, using 'eval' doesn't teach you anything about scoping 
and recursion in objects, which is presumably the point of the exercise.

> 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.

This should be straightforward.

What expression recognizes the case where the method name is 'setx and 
there is one argument?

 > 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?

Why can't you give it a label?

I recommend thinking carefully about what names need to be in scope in 
each lambda expression. Can you make an expression that gets the scopes 
right?

Ryan


> 
> Sorry for the long explanation for what boils down to a simple question, and 
> thanks in advance for any help.
> 
> - David Johnson
> 
> _________________________________________________
>   For list-related administrative tasks:
>   http://list.cs.brown.edu/mailman/listinfo/plt-scheme



Posted on the users mailing list.