Re: Three questions
- From: tar@xxxxxxxxxxxxx (Thomas A. Russ)
- Date: 18 Jun 2009 17:21:19 -0700
vippstar <vippstar@xxxxxxxxx> writes:
You really are making this harder on yourself than it needs to be. Most
of the functionality you are doing here already exists in lisp.
1. (defun foo () (bar)) does equivalent work to
(setf (symbol-function 'foo)
(lambda () (bar)))
plus some bookkeeping work (implementation details).
Should a macro that temporarily uses a new value for
(symbol-function 'name) be used? For instance,
(defun f (x) (1+ x))
(with-funcs ((f . (lambda (x) (1- x)))
(print (f 0)))
(print (f 0))
Well, you could already just use the FLET or LABELS form to do what you
want. It would look like:
(defun f (x) (1+ x))
(flet ((f (x) (1- x)))
(f 0)) ==> -1
(f 0) ==> 1
By the way, if it's the last form, then you don't even need to invoke
PRINT, since the value of the last form will be printed anyway by Lisp's
read-eval-print loop. If you put the print in there, then you'll see
every value twice.
==> -1
1
Another way to implement this macro, assuming its
argument list is (defs &body body), is to search body
for occurances of the symbols in (mapcar #'car defs),
and replace them with FUNCALLs of the corresponding
CARs in the list (mapcar #'cdr defs)
Well, you COULD do that, but you would have to be careful that you
really understand all of the binding forms in Common Lisp and also make
sure that you do proper macro-expansion of any macro forms.
In general, writing a code-walker is a pretty advanced project.
2. Macros, among other things, can be used to extend
the language. To which extend is this true? In other
words, which set of code is the fundamental for a lisp
limplementation? Presumably this code offers all the
features lisp has which can't be implemented with
macros. These features along with anything macros
can be used for define the extensibility of the language.
Well, language extension happens in a number of ways. Macros play a
part in that, mainly because they let you control evaluation, which is
often KEY for properly implementing control structures. It is also
highly useful for designing domain-specific languages.
But in general, one doesn't really need to worry about the core part of
Lisp unless you are doing a ground-up new implementation of lisp.
Instead, you just leave the Common Lisp functions as they are and
implement your additions to the language as additions, not replacements.
If you really have very extensive modifications, you would typically
then define your own package that does not :USE the COMMON-LISP package.
You then have a lot more control over what symbols are present.
Is there any material that documents the former?
Is it possible to add features to this list? Would it be
necessary to touch the implementations source?
It shouldn't be necessary for you do to anything to the implementation.
That's one of the best parts of lisp extensions. It would be quite the
rare occurrence for you to have to do anything to the underlying code
base. Note that this applies to EXTENDING Common Lisp and not CHANGEING
it.
But there is a (hard-to-find?) book, "Lisp in Small Pieces" that goes
into detail about low-level implementation issues.
3. I wrote this macro
(defmacro temporarily (name new-value &body body)
(with-gensyms (g)
`(let ((,g ,name))
(setf ,name ,new-value)
(unwind-protect
(progn ,@body)
(setf ,name ,g)))))
Now, if a set of functions has been designed with
*global* variables to use (probably poor terminology
to the ears of a lisper), this macro can be used to
abstract away and hide them in parameters.
If MY-CAR has been designed to return the car of *list*,
and we wished to change MY-CAR to work like CAR,
we could write:
(defun my-car2 (list) (temporarily *list* list (my-car)))
Again, this is already the normal function of LET binding of global
variables. You would just write
(defun my-car2 (list)
(let ((*list* list))
(my-car)))
and you would be done. Common Lisp already has a lot of this flexibilty
already built in.
Do you think that is good style? I find it very convenient
to write code like that. I'm aware that for a large project
these function calls should be rewritten to work with
local bindings, to avoid unnecessary calls to functions
such as MY-CAR2 which set the environment and then
call the real thing, in my example MY-CAR.
Well, no, I don't really approve of this style.
1. You should just use the existing structures that do what you want.
2. You really should try to use function parameters, unless the items
you are manipulating are some type of global state, or if they have
some sort of control function that crosses many levels of function
call (like the printer control variables or *standard-output* and
friends in Common Lisp)
(another important thing to note is that this macro would
misbehave if used by concurrently processes)
Well, there is that as well.
Lastly, I've tried but I'm unable to write a version that
works for multiple bindings, which would hypothetically
be used as:
(temporarily ((name1 . val1) (name2 . val2)) body-code)
Any hints/takes on this?
You need to write some code that builds up the list of bindings by
iterating over the inputs. That is actually a nice macro exercise,
since it shows you you can use lisp program code to compute the
transformation of your values. In this case, it ends up being fairly
trivial, since all you are doing is taking a dotted list and
transforming it into a proper list. But it is work doing.
My choice would be to use LOOP for the job.
Also, I find it helpful when designing macros to take an example use of
the macro and then, by hand, write the code that I want to have the
macro produce. Then I work backwards toward having the macro compute
that expansion.
Since you just asked for hints, I'll leave it at that for now.
--
Thomas A. Russ, USC/Information Sciences Institute
.
- Follow-Ups:
- Re: Three questions
- From: Rob Warnock
- Re: Three questions
- References:
- Three questions
- From: vippstar
- Three questions
- Prev by Date: Re: Clojure
- Next by Date: Re: Three questions
- Previous by thread: Re: Three questions
- Next by thread: Re: Three questions
- Index(es):
Relevant Pages
|