[comp.lang.lisp] lisp problem

yushen@deimos.ads.com (Yu-shen Ng) (08/04/88)

(eval form) normally evaluates "form" in a null lexical scope.

How can I do an "eval" within the lexical scope from which the "eval" is called?
     e.g. I would like to do the following:

       (defun test ()
	 (let ((form)
	       (a ..)
	       (b ..)
	       (c ..)
	       (any-number-of-variables 
		    ....
		       ))
           ... 
	   ...
	   (eval form)))       ; where "form" may reference any of the variables
                               ;  in the lexical scope when eval is called.
	 
Suppose that you do not even know the names of all the local variables
	that "form" may reference.

It seems to me that you have to use *evalhook* and evalhook, but I can't seem to get them to
  work for me for any general "form".


Please send any helpful ideas to

yushen@ads.com

barmar@think.COM (Barry Margolin) (08/04/88)

In article <5071@zodiac.UUCP> yushen@ads.com (Yu-shen Ng) writes:
>How can I do an "eval" within the lexical scope from which the "eval" is called?

You can't.  EVAL is an ordinary function, so it has no idea what
lexical context it was called in (only special forms and macros can
access the lexical context).

How would it possibly work in a compiled function, when references to
lexical variables have been converted to stack frame offsets, and the
names of the local variables have been discarded?  If the Lisp
implementation saves the local variable information (as it does on
Lisp Machines) then there will likely be an implementation-specific
function for evaluating in a given lexical environment (for use by the
debugger, for instance); a common mechanism is to allow EVAL to take
an optional second argument, which is the lexical environment.
However, Common Lisp doesn't require this capability.

Why do you need this capability?  If the form you want to evaluate is
coming from outside the function, how could it possibly know the names
of your local variables?

Perhaps you should describe what you are trying to accomplish, since I
suspect you may be going about it wrong.  It is almost always wrong to
call EVAL explicitly from a function.  You can usually do what you
want with FUNCALL or APPLY.

Barry Margolin
Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

jeff@aiva.ed.ac.uk (Jeff Dalton) (08/12/88)

In article <5071@zodiac.UUCP> yushen@ads.com (Yu-shen Ng) writes:
>(eval form) normally evaluates "form" in a null lexical scope.  How can
>I do an "eval" within the lexical scope from which the "eval" is called?

>It seems to me that you have to use *evalhook* and evalhook, but I can't
>seem to get them to work for me for any general "form".

You can indeed use *EVALHOOK* and EVALHOOK in interpreted code (see
below), but the trick will not work for compiled code.  Common Lisp
does not encourage this style of programming because it makes life
difficult for the compiler and because code written that way is often
hard to analyze.  Nonetheless, it would be possible to implement a
Lisp in which EVAL did work with lexical environments.

Since EVAL is a function, it must be given the environment as a
parameter. That implies that the environment is an explicit object,
and while interpreters may use such objects, compiled code often does
not.  However, suppose there were a special form that returned a
lexical environment.  The compiler could notice the presence of that
operation and use an explicit structure only then.  [Or, if EVAL were
a special form, it could do this for EVAL.]  Compilers already make a
similar analysis for closures, which also must include an environment.
[However, the closure env is not necessarily one in which values can
be looked up by name -- since the variables involved can all be known
at compile time, the code could just use an offset.]

The idea here is that something, (GET-ENV) perhaps, would return the
current lexical environment "around" the GET-ENV call.  This can be
done for interpreted CL as follows:

;;; Return the current lexical environment.

(defmacro get-env ()
  '(let ((*evalhook*
          #'(lambda (form &optional env) env)))
     (eval 'nil)))

;;; Eval w.r.t. an environment

(defun enveval (form lexenv)
  (evalhook form nil nil lexenv))

Now, 

   > (let ((a 10)) (get-env))
   #<an environment>
   > (enveval 'a *)
   10

Another appraoch is to provide an environment for certain names only.
This is something you can write yourself -- Lisp doesn't have to provide
it.

>Suppose that you do not even know the names of all the local variables
>	that "form" may reference.

It may be inconvenient, but you often can know the names simply by
looking at the code around the EVAL.  This will not work if the EVAL
is part of a macro expansion.  An alternative to listing the names to
put in the environment is to define varsions of LET, FLET, etc. that
make their bindings visible to GET-ENV.  At this point, you might be
better off using dynamic scoping instead, but perhaps you want
closures over these variables too.  Anyway, below is some code that
does this for LET.

     ------------------------------------------------------------

;;; Visible let [vlet] -- makes bindings visible to get-env.

(defmacro vlet (binds &body body)
  ;; syntax is (VLET ((var init)...) form...)
  `(vlet-1 () ,binds ,@body))

;;; vlet-1 redefines vlet to keep track of nesting.
;;; It also defines get-env to return an env that allows
;;; ref to everything bound by vlet.

(defmacro vlet-1 (nest binds &body body)
  (let ((nest (append nest (mapcar #'car binds))))
    `(let ,binds
       (macrolet
	   ((vlet (binds &body body)
	      `(vlet-1 ,',nest
		       ,binds
		       ,@body))
	    (get-env ()
	      `(enclose ,',nest)))
	 ,@body))))

;;; A lexical environment is represented by a structure containing
;;; functions that access or set the variables.

(defstruct (lexenv (:print-function print-lexenv))
  names getter setter)

(defun print-lexenv (lexenv stream depth)
  (format stream "#<Lexenv ~S>"
	  (mapcar #'(lambda (name)
		      (list name (symeval-in-env lexenv name)))
		  (lexenv-names lexenv))))

;;; Enclose makes an env struct for the variables indicated.
;;; It must be called in a context where the variables are
;;; lexically visible.

(defmacro enclose (vars)
  `(make-lexenv
     :names ',vars
     :getter
       #'(lambda (name)
	   (ecase name
	     ,@(mapcar #'(lambda (v) `(,v ,v))
		       vars)))
     :setter
       #'(lambda (name val)
	   (ecase name
	     ,@(mapcar #'(lambda (v) `(,v (setq ,v val)))
		       vars)))))

;;; Functions for getting and setting variables in environments.

(defun symeval-in-env (env name)
  (funcall (lexenv-getter env) name))

(defun set-in-env (env name val)
  (funcall (lexenv-setter env) name val))

(defsetf symeval-in-env set-in-env)

;;; Eval relative to an environment.  Symbol-macro-let is used
;;; to turn variable references into function calls that look
;;; in the environment.  Symbol-macro-let is to let what macrolet
;;; is to flet (or is it labels?); it is part of CLOS.

(defun enveval (form env)
  ;; needs symbol-macro-let
  (eval
   `(let ((the-env ',env))
      (symbol-macro-let
          ,(mapcar #'(lambda (name)
		       `(,name (symeval-in-env the-env ',name)))
		   (lexenv-names env))
	  ,form))))

     ------------------------------------------------------------

This code is provided primarily for entertainment value; I don't claim
it's a good way to do anything.  Nonetheless, through the magic of
macros, it does not create an environment unless GET-ENV is actually
called.

Jeff Dalton,                      JANET: J.Dalton@uk.ac.ed             
AI Applications Institute,        ARPA:  J.Dalton%uk.ac.ed@nss.cs.ucl.ac.uk
Edinburgh University.             UUCP:  ...!ukc!ed.ac.uk!J.Dalton

layer@snooze.UUCP (Kevin Layer) (08/18/88)

    Article 1137 of 1140, Wed 14:04.
    Subject: LISP PROBLEM
    From: yushen@deimos.ads.com (Yu-shen Ng)
    Organization: Advanced Decision Systems, Mt. View, CA (415) 960-7300

    (eval form) normally evaluates "form" in a null lexical scope.

    How can I do an "eval" within the lexical scope from which the
    "eval" is called?

In Allegro CL you can use excl::%eval.  For example,

    user-7> (defun test ()
	      (let ((form '(format t "foo ~s~%" a))
		    (a 10))
		(excl::%eval form)))

    test 
    user-8> (test)
    foo 10

    nil 
    user-9> 

-Kevin

canoura@ihlpl.ATT.COM (jlcanoura) (04/11/89)

PLEASE, does anybody know how to solve this problem in LISP.

By using recursion and the Append function, Given a list of
nondistinct elements and a positive number K where K is <=
the size of the list, I need to write a function which returns
a list, the element of whose are the combinations of the 
element of the given list taken K at a time. 
e.g.(COMB '(n1 n2 ....n) K)

Examples. ( COMB is the name of the function)

(COMB '(1 2 3 ) 2) should return  
  ((1 2) (1 3) (2 3))

(COMB '(1 2 3) 3) should return
  ((1 2 3))

(COMB '(1 2 3) 1) should return
  ((1) (2) (3))

etc.


any help will be apreciated.


                                           ihlpl!canoura

dorai@titan.rice.edu (Dorai Sitaram) (04/11/89)

In article <10053@ihlpl.ATT.COM> canoura@ihlpl.ATT.COM (jlcanoura) writes:
$PLEASE, does anybody know how to solve this problem in LISP.
$
$By using recursion and the Append function, Given a list of
$nondistinct elements and a positive number K where K is <=
$the size of the list, I need to write a function which returns
$a list, the element of whose are the combinations of the 
$element of the given list taken K at a time. 
$e.g.(COMB '(n1 n2 ....n) K)
$
$Examples. ( COMB is the name of the function)
$
$(COMB '(1 2 3 ) 2) should return  
$  ((1 2) (1 3) (2 3))
$
$(COMB '(1 2 3) 3) should return
$  ((1 2 3))
$
$(COMB '(1 2 3) 1) should return
$  ((1) (2) (3))

(defun comb (s k)
  (cond ((zerop k) (list nil))
	((null s) nil)
	(t (let ((a (car s)) (s1 (cdr s)))
	     (append (mapcar #'(lambda (c) (cons a c)) (comb s1 (1- k)))
		     (comb s1 k))))))

Regards,

--dorai
------------------------------------------------------------------------------
We must believe in free will. We have no choice.       --Isaac Bashevis Singer
------------------------------------------------------------------------------

johnson@csli.STANFORD.EDU (Mark Johnson) (04/12/89)

#| /*
canoura@ihlpl.ATT.COM asks...

By using recursion and the Append function, Given a list of
nondistinct elements and a positive number K where K is <=
the size of the list, I need to write a function which returns
a list, the element of whose are the combinations of the 
element of the given list taken K at a time. 
e.g.(COMB '(n1 n2 ....n) K)

Examples. ( COMB is the name of the function)

(COMB '(1 2 3 ) 2) should return  
  ((1 2) (1 3) (2 3))

(COMB '(1 2 3) 3) should return
  ((1 2 3))

(COMB '(1 2 3) 1) should return
  ((1) (2) (3))
  */

/* Here is the complete prolog program to solve this problem! */

sublist([],[]).
sublist([E|S],[E|L]) :- sublist(S,L).
sublist(S,[_|L]) :- sublist(S,L).

/*  Here's a sample run 

?- length(L,2),sublist(L,[1,2,3]).  % length is built-in in my Prolog
L = [1,2] ;
L = [1,3] ;
L = [2,3] ;
No more solutions.

*/
|#

;;; Now we switch to Lisp
;;;
;;; We use the standard trick of modelling a Prolog procedure
;;; with a Lisp procedure plus an accumulator (here called 'so-far').
;;; We loose the neat pattern matching abilities of Prolog in Lisp,
;;; so we approximate them with the additional argument 'elts-needed'.
;;;
;;; It doesn't have the brevity of the Prolog solution, but the essential
;;; recursive structure is still visible (if you squint a bit).  Note
;;; that it is pure Lisp (in the real sense, not even iteration).

(defun comb (elts n)
  (labels ((try (so-far partial-soln remaining-elts elts-needed)
             (if (= elts-needed 0)
               (cons partial-soln so-far)
               (if (consp remaining-elts)
                 (try (try so-far 
                           (cons (first remaining-elts) partial-soln)
                           (rest remaining-elts)
                           (1- elts-needed))
                      partial-soln
                      (rest remaining-elts)
                      elts-needed)
                 so-far))))
    (try '() '() elts n)))

#|
? (comb '(1 2 3) 2)
((3 2) (3 1) (2 1))
? (comb '(1 2 3 4) 3)
((4 3 2) (4 3 1) (4 2 1) (3 2 1))
|#

;;; You can get the order required in the original problem by reversing
;;; each list before it is put on the accumulator.