Hello,
I'm a relative Common Lisp beginner, and I'm hoping that a Lisp expert can
assist me a bit with a program I'm writing... here's a simpler example of what
I'm trying to do:
(defun f2 (x)
(eval (second (get-a-list))))
(defun get-a-list ()
'( (+ 2 2) (+ 2 x) (+ 3 3)))
I'd like for function f2 to evaluate (+ 2 x) for the value of x bound in f2,
but when the Lisp interpreter tries to execute the eval, it says that variable x
is not bound. I've tried using the backquote and comma operators in various
ways, but without success. How can I make this work? (this example is
contrived, but I hope you see the concept I'm after here)
I appreciate any replies & followups
a
Alex Graf <·····@sfu.ca> writes:
> I'm a relative Common Lisp beginner,
Welcome.
> I'm trying to do:
>
> (defun f2 (x)
> (eval (second (get-a-list))))
> (defun get-a-list ()
> '( (+ 2 2) (+ 2 x) (+ 3 3)))
>
> I'd like for function f2 to evaluate (+ 2 x) for the value of x bound in f2,
> but when the Lisp interpreter tries to execute the eval, it says that
> variable x is not bound.
Variables in Common Lisp are, by default, lexically scoped. Very
approximately, this means they are available within the visual region
of text between the parentheses of the form that established their
binding. Since the X you wrote is bound by the defun of F2, it
is defaultly available only within F2. This does not include the
"dynamic scope" of that definition--that is, others definitions called
by that program are not automatically annexed by virtue of said call.
The simple answer to your question is that you need to add a special
declaration for X, as in:
(defun f2 (x)
(declare (special x))
...)
This will declare that the X bound in F2 should be made available as
a special variable. That will mean other references that are declared
special (even in other definitions) will see the binding, and free
references in EVAL will generally see it.
It's really not good style to do what you're doing though. A good
rule of thumb for beginners is:
(1) Don't use special declarations.
(2) Don't use EVAL.
It's not that these functions should never be used. But their correct
use is so rare that if you're a beginner, chances are that you don't
have a legitimate use unless you're just fooling around and filing the
information away for possible future use.
> I've tried using the backquote and comma operators in various
> ways, but without success.
This wouldn't work unless you had bound X properly in GET-A-LIST. e.g.,
(defun f2 (x)
(eval (second (get-a-list x))))
(defun get-a-list (x)
`( (+ 2 2) (+ 2 ,x) (+ 3 3)))
I wouldn't say this is particularly good style either, since it conses
a lot of lists just in case one of them has an X in it. e.g.,
if you did
(defun f1 (x)
(eval (first (get-a-list x))))
you'd end up making a new list with X substituted in, but then you'd grab
a sublist that didn't have that X used, and that's kind of storage-wasteful.
> How can I make this work? (this example is
> contrived, but I hope you see the concept I'm after here)
Contrived examples are fine, especially if you know that's what
you're doing. Homework examples, if you're doing this for a class,
should be labeled as such. I'm assuming this is not a homework
example, though.
> I appreciate any replies & followups
Good luck.
Thanks very much for your reply. You are right that this is not homwork, I am
an amateur Lisp programmer. I have heard before that EVAL and SET forms should
generaly not be used, but I would be very interested in some references to
professional code where they are actually required.
The program I am writing uses a kind of "object system" of my own design, which
allows for objects to trade methods with each other and/or obtain new ones,
during runtime. Internally I store code for methods in an association
list. Probably my whole object design is quite flawed, but I've written enough
code around it that I'd like to carry on with it if possible. I think special
declaration should do the trick in this instance.
The function I am writing to execute object methods is actually this.
I would like for the code retrieved into "action" to be able to use data that
arg1 is bound to
; description: performs the action a associated with thing tg,
; if there is such an action in tg.
;
(defun exec-action (tg a arg1)
(check-type tg thing)
(check-type a symbol)
(let* ((actions-list (t-actions tg))
(action (second (assoc a actions-list :test 'equal))))
(if (null action)
t
(eval action))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
On Sat, 03 Apr 1999, Kent M Pitman wrote:
>Alex Graf <·····@sfu.ca> writes:
>
>> I'm trying to do:
>>
>> (defun f2 (x)
>> (eval (second (get-a-list))))
>> (defun get-a-list ()
>> '( (+ 2 2) (+ 2 x) (+ 3 3)))
>>
>> I'd like for function f2 to evaluate (+ 2 x) for the value of x bound in f2,
>
>The simple answer to your question is that you need to add a special
>declaration for X, as in:
>(defun f2 (x)
> (declare (special x))
> ...)
>It's really not good style to do what you're doing though. A good
>rule of thumb for beginners is:
> (1) Don't use special declarations.
> (2) Don't use EVAL.
>It's not that these functions should never be used. But their correct
>use is so rare that if you're a beginner, chances are that you don't
>have a legitimate use unless you're just fooling around and filing the
>information away for possible future use.
In article <············@morgoth.sfu.ca>,
Alexander Robert Graf <·····@sfu.ca> wrote:
>The program I am writing uses a kind of "object system" of my own design, which
>allows for objects to trade methods with each other and/or obtain new ones,
>during runtime. Internally I store code for methods in an association
>list. Probably my whole object design is quite flawed, but I've written enough
>code around it that I'd like to carry on with it if possible. I think special
>declaration should do the trick in this instance.
It would probably require significant redesign, but usually the right way
to do this type of thing is with lexical closures, not special variables
and EVAL. Special variables should be used sparingly, because referential
transparency can be violated. The canonical example of this comes from an
implementation of MAPC in a dynamically-scoped Lisp:
(defun mapc (f list)
(dolist (x list)
(funcall f x)))
If you then do:
(let ((f "F"))
(mapc #'(lambda (i) (print (list f i)))
'(1 2 3)))
Instead of printing
("F" 1)
("F" 2)
("F" 3)
it will print something like:
(#<function> 1)
(#<function> 2)
(#<function> 3)
Of course, it may not be so bad in your application, where only selected
variables will be special and only in certain contexts. But you still need
to be very careful.
--
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
First a few remarks on the definition of EXEC-ACTION, then on to
the main issue.
In article <············@morgoth.sfu.ca>,
·····@sfu.ca (Alexander Robert Graf) wrote:
(...)
> The function I am writing to execute object methods is actually this.
> I would like for the code retrieved into "action" to be able to use data
> that arg1 is bound to
>
> ; description: performs the action a associated with thing tg,
> ; if there is such an action in tg.
> ;
> (defun exec-action (tg a arg1)
"Performs the action a associated with thing tg, if there is such
an action in tg, while passing arg1 to the action, and returns the
produced result, otherwise returns T."
I.e. a doc-string is better than a comment for this purpose.
> (check-type tg thing)
> (check-type a symbol)
> (let* ((actions-list (t-actions tg))
> (action (second (assoc a actions-list :test 'equal))))
(1) It is unusual to use SECOND and not CDR to obtain the value
associated with the key when using a-lists.
If the entries in the a-list do not have the simple structure
of (action-id . action) but something like (action-id action other...)
(which may be the case here, I don't know), it would be better to
introduce a specific abstraction for accessing an actions-list to be
used e.g. like this:
(let ((action (get-action a (t-actions tg)))) ;just one local variable,
...) ; LET* not really needed
No matter what the structure of the entries is, this is good as
it has the obvious added benefit that if you decide to use
e.g. hash tables instead of a-lists for faster access or whatever,
you will need to make fewer changes to the program.
(2) Why :TEST #'EQUAL and not the default EQL test when A is a symbol?
> (if (null action)
> t
> (eval action))))
^^ looks like missing indentation here
Now to the main issue about the variable bindings.
Let me first say that when I saw the above definition, before realising
that the purpose of ARG1 is to be bound so that the evaluation of ACTION
uses it, there was a short but sufficient time for the thought, what is
an unused variable doing here? So you should also take into account the
fact that such code is a little harder to read.
The above code would do what is expected if there is
(defvar arg1 nil "Argument passed to actions when they are executed.")
somewhere earlier in your program.
Besides the other shortcomings of this approach (using a special
variable and EVAL), this forces you to always use the same symbol,
ARG1, for the action parameter in the actions themselves.
If you are definitely sure that actions will never need more than
a single parameter, I would suggest the following (in the spirit of
one of the earlier suggestions (by Steve Gonedes, I think)):
* don't make ARG1 special;
* make all actions functions of a single variable, i.e. an action
would be either something like:
#'(lambda (arg)
(declare (ignore arg))
(+ 2 2))
or something like
#'(lambda (x) (+ x 2))
and the name of the parameter can be any that clearly shows its
particular purpose for the action;
* instead of (EVAL ACTION), say (FUNCALL ACTION ARG1).
If you would also like to have multiple arguments passed to
actions, and different arglists for the different actions, one
possibility would be to use &REST ARGS with EXEC-ACTION as well
as in the lambda-lists of the actions, and then have the
actions do DESTRUCTURING-BIND (a very useful tool) to get to
their actual arguments.
One final note: while PROGV may provide you with a working program
quickly, it may lead to problems or `biting bugs' later on, so
caveat emptor as usual.
Good luck,
Vassil.
Vassil Nikolov <········@poboxes.com> www.poboxes.com/vnikolov
(You may want to cc your posting to me if I _have_ to see it.)
LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
Vassil Nikolov <········@poboxes.com> writes:
> > (check-type tg thing)
> > (check-type a symbol)
> > (let* ((actions-list (t-actions tg))
> > (action (second (assoc a actions-list :test 'equal))))
>
> (1) It is unusual to use SECOND and not CDR to obtain the value
> associated with the key when using a-lists.
Personal style. I almost never use alists as (key . val). I hate
seeing the dot. I use (key val). Also, if you use the (key val)
style, it leaves "syntactic room" to later add more things associated
with key. If you use (key . val), there is no room for later extension
if there is another item you want to put into the table with key.
In fact, though, I often just use lists of objects and use FIND with
a :KEY argument instead of alists these days.
·····@sfu.ca (Alexander Robert Graf) writes:
> Thanks very much for your reply. You are right that this is not
> homwork, I am an amateur Lisp programmer. I have heard before that
> EVAL and SET forms should generaly not be used, but I would be very
> interested in some references to professional code where they are
> actually required.
An example similar to what you show below is a good use of EVAL, I
think, as long as most of your system is not going to use EVAL and the
action is something you're doing as an interface to a text file that
will change frequently without wanting to recompile the system. An
"init file" is an example of something that implicitly uses EVAL
effectively, although in practice one uses LOAD rather than EVAL for
that, and you might want to just use LOAD yourself in many such
things.
> The program I am writing uses a kind of "object system" of my own
> design, which allows for objects to trade methods with each other
> and/or obtain new ones, during runtime. Internally I store code for
> methods in an association list.
Unless you're going to have the methods introspect about the parts
of the code, you're better off storing functions (preferrably compiled)
since they'll be faster to call and will be optimized if appropriate.
> Probably my whole object design is quite flawed, but I've written
> enough code around it that I'd like to carry on with it if possible.
> I think special declaration should do the trick in this instance.
Before you decide this, make sure you don't want either lexical closures
or just argument-passing. For example:
(defvar *my-functions* (make-array 10 :adjustable t :fill-pointer 0))
(defun f (n x)
(funcall (aref *my-functions* n) x))
(defun add-a-function (function)
(vector-push-extend function *my-functions*)
(length *my-functions*))
(add-a-function #'(lambda (x) (declare (ignore x)) (+ 2 2)))
=> 0
(add-a-function #'(lambda (x) (+ x 2)))
=> 1
(f 0 3) => 4
(f 1 3) => 5
> The function I am writing to execute object methods is actually this.
> I would like for the code retrieved into "action" to be able to use
> data that arg1 is bound to
>
> ; description: performs the action a associated with thing tg,
> ; if there is such an action in tg.
> ;
> (defun exec-action (tg a arg1)
> (check-type tg thing)
> (check-type a symbol)
> (let* ((actions-list (t-actions tg))
> (action (second (assoc a actions-list :test 'equal))))
> (if (null action)
> t
> (eval action))))
You're better off just unconditionally evaluating the action. Doing
(eval action) when action is NIL won't take that much longer than
just returning T. And NIL is a better return value in the case that
nothing was done anyway.
But you should really rewrite this to grab functions and do
(funcall action arg1)
instead of
(eval action)
If you do this rewrite, then you will have to handle NIL specially because
you can't FUNCALL it. Here's one way to do that:
(funcall (or action #'identity) arg1)
Alex Graf <·····@sfu.ca> writes:
< (defun f2 (x)
< (eval (second (get-a-list))))
< (defun get-a-list ()
< '( (+ 2 2) (+ 2 x) (+ 3 3)))
<
< I'd like for function f2 to evaluate (+ 2 x) for the value of x
< bound in f2, but when the Lisp interpreter tries to execute the
< eval, it says that variable x is not bound. I've tried using the
< backquote and comma operators in various ways, but without success.
< How can I make this work? (this example is contrived, but I hope you
< see the concept I'm after here)
I rember having trouble with something like this as well. You can use
a lambda form and funcall/apply.
(defun get-a-list ()
(list (lambda () (+ 2 2))
(lambda (x) (+ x 2))
(lambda () (+ 3 3))))
(funcall (second (get-a-list)) 4) => 6.
You could also use progv.
(defun get-a-list ()
'((+ 2 2) (+ x 2) (+ 3 3)))
(defun f2 (value)
(let* ((form (second (get-a-list)))
(variable-names (remove-if-not #'symbolp (rest form))))
(progv variable-names (list value)
(values (eval form)
variable-names
(mapcar #'identity variable-names)
(mapcar #'symbol-value variable-names)
;; The following is usually not advisable
(list x)))))
(f2 4) => 6, (x), (x), (4), (4)
I think of `progv' as making temporary special variables at runtime.
You can't use a `special' declaration because you don't know the
variable name. If you know the variable names ahead of time like I did
with `(list x)', you can do the following.
(defun f3 (value)
(let ((x value))
(declare (special x))
(eval (second (get-a-list)))))
(f3 5) => 7.
It's usually suggested that special variables be named with a leading
and ending `*' though.
You could reconstruct the entire form and then call funcall/apply/eval.
(defun f4 (value &optional (variable-name 'x))
(let ((form (second (get-a-list))))
(subst value variable-name form)))
(f4 6) => (+ 6 2)
You might be better off using apply or funcall instead of eval unless
you had something like the following:
(defun get-a-list ()
'((+ 1 2) (* (+ 2 x) x) (+ 3 3)))
(f4 9) => (* (+ 2 9) 9).
< I appreciate any replies & followups
Hope this helps some.