How do I create a quoted list in Lisp that uses the symbols' values in the list, rather than the symbols themselves? For example, take two variables foo and bar, foo = "hello" and bar = "world". How do I get a list that contains "hello" "world" from these two variables. The best thing I can think of is this:
;; This is Emacs Lisp
(let ((foo "hello")
(bar "world"))
(message (prin1-to-string '(foo bar)))
;; prints "(foo bar)"
But this is wrong. What's the right way to do this?
Never mind, further experimentation revealed that the answer is (list foo bar).
(let ((foo "hello")
(bar "world"))
(message (prin1-to-string (list foo bar)))
;; prints '("hello" "world")'
EDIT: Another way of achieving this is using `(,foo ,bar)
(let ((foo "hello")
(bar "world"))
(message (prin1-to-string `(,foo ,bar)))
;; prints '("hello" "world")'
This is a rather strange question since if you want the value of foo and bar you are not suppose to quote it. Using only primitives you make such list:
(let ((foo "hello")
(bar "world"))
(cons foo (cons bar nil))) ; ==> ("hello" "world")
There is a function called list that does the cons for you, thus (list foo bar 'foo 'bar) does the same as (cons foo (cons bar (cons 'foo (cons 'bar nil)))) ==> ("hello" "world" foo bar) in the same scope as the code above.
With quasiquoting (backquoting) you can mix constants so that `(,foo ,bar foo bar) is the equivalent, but be aware that constant tails, like '(foo bar) in my example, get reused.
Related
(defmacro foo (x)
`(defun ,xt ()
(format t "hullo")))
(foo bar)
will not define a function bart, since ,xt is read as the variable xt rather than the variable x plus a t. But is there a way to get a function bart by supplying the argument bar?
You need to create the function name (which is a string then) and then convert it to a symbol, for example:
(defmacro foo (x)
`(defun ,(intern (format nil "~aT" x)) ()
(format t "hullo")))
then
? (foo bar)
BART
? (bart)
hullo
NIL
What is the fundamental difference in the functions defined using defun and setf as below and is one method preferred over another outside of style considerations?
Using defun:
* (defun myfirst (l)
(car l) )
MYFIRST
* (myfirst '(A B C))
A
Using setf:
* (setf (fdefinition 'myfirst) #'(lambda (l) (car l)))
#<FUNCTION (LAMBDA (L)) {10021B477B}>
* (myfirst '(A B C))
A
If, as according to Wikipedia:
named functions are created by storing a lambda expression in a symbol using the defun macro
Using setf to create a variable in a different way requires the use of funcall:
* (defvar myfirst)
MYFIRST
* (setf myfirst (lambda (l) (car l)))
#<Interpreted Function (LAMBDA (X) (+ X X)) {48035001}>
* (funcall myfirst '(A B C))
A
My understanding is that this type of variable is different than the previous in that this variable is not found in the same namespace as the defun bound symbol as described in Why multiple namespaces?.
First of all, one should never underestimate the importance of style.
We write code not just for computers to run, but, much more importantly, for people to read.
Making code readable and understandable for people is a very important aspect of software development.
Second, yes, there is a big difference between (setf fdefinition) and defun.
The "small" differences are that defun can also set the doc string of the function name (actually, depending on how your imeplementation works, it might do that with lambda also), and creates a named block (seen in the macroexpansions below) which you would otherwise have to create yourself if you want to.
The big difference is that the compiler "knows" about defun and will process it appropriately.
E.g., if your file is
(defun foo (x)
(+ (* x x) x 1))
(defun bar (x)
(+ (foo 1 2 x) x))
then the compiler will probably warn you that you call foo in bar with the wrong number of arguments:
WARNING: in BAR in lines 3..4 : FOO was called with 3 arguments, but it requires 1
argument.
[FOO was defined in lines 1..2 ]
If you replace the defun foo with (setf (fdefinition 'foo) (lambda ...)), the compiler is unlikely to handle it as carefully. Moreover, you will probably get a warning along the lines of
The following functions were used but not defined:
FOO
You might want to examine what defun does in your implementation by macroexpanding it:
(macroexpand-1 '(defun foo (x) "doc" (print x)))
CLISP expands it to
(LET NIL (SYSTEM::REMOVE-OLD-DEFINITIONS 'FOO)
(SYSTEM::EVAL-WHEN-COMPILE
(SYSTEM::C-DEFUN 'FOO (SYSTEM::LAMBDA-LIST-TO-SIGNATURE '(X))))
(SYSTEM::%PUTD 'FOO
(FUNCTION FOO
(LAMBDA (X) "doc" (DECLARE (SYSTEM::IN-DEFUN FOO)) (BLOCK FOO (PRINT X)))))
(EVAL-WHEN (EVAL)
(SYSTEM::%PUT 'FOO 'SYSTEM::DEFINITION
(CONS '(DEFUN FOO (X) "doc" (PRINT X)) (THE-ENVIRONMENT))))
'FOO)
SBCL does:
(PROGN
(EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN 'FOO NIL T))
(SB-IMPL::%DEFUN 'FOO
(SB-INT:NAMED-LAMBDA FOO
(X)
"doc"
(BLOCK FOO (PRINT X)))
(SB-C:SOURCE-LOCATION)))
The point here is that defun has a lot "under the hood", and for a reason. setf fdefinition is, on the other hand, more of "what you see is what you get", i.e., no magic involved.
This does not mean that setf fdefinition has no place in a modern lisp codebase. You can use it, e.g., to implement a "poor man's trace" (UNTESTED):
(defun trace (symbol)
(setf (get symbol 'old-def) (fdefinition symbol)
(fdefinition symbol)
(lambda (&rest args)
(print (cons symbol args))
(apply (get symbol 'old-def) args))))
(defun untrace (symbol)
(setf (fdefinition symbol) (get symbol 'old-def))
(remprop symbol 'odd-def))
FUZZ> (defvar *foo* nil)
*FOO*
FUZZ> (defmacro bar ()
(format t "foo: ~A" *foo*)
`(+ 1 1))
BAR
FUZZ> (defmacro bot ()
(let ((*foo* 17))
`(bar)))
BOT
FUZZ> (bot)
foo: NIL
My mental model (clearly wrong) of macro expansion says the following happens in order:
Run the macro expansion of bot (which binds *foo* to 17), run the macro expansion of bar, which prints the current value of *foo* (being 17), and returns the form (+ 1 1), which is not a macro, macro expansion time is now over, finally evaluate the form (+ 1 1), and returns 2.
Why am I wrong?
Is there an easy way to do what I intend?
When the REPL is told to evaluate (bot), it first has to perform macroexpansion. It calls the macroexpansion function bot, which means, in effect, evaluating
(let ((*foo* 17))
`(bar))
That returns (bar) and then the binding of from let is unwound. Now we've got (bar). bar is a macro, so it's time for another round of macroexpansion, which means evaluating
(progn
(format t "foo: ~a" *foo*)
`(+ 1 1))
which prints foo: NIL, and returns (+ 1 1).
If you want the macroexpansion to be performed in the scope of some bindings, you'll need to call the macroexpansion function yourself. E.g., you can use macroexpand:
CL-USER> (defparameter *foo* nil)
*FOO*
CL-USER> (defmacro bar ()
(format t "foo: ~a" *foo*)
`(+ 1 1))
BAR
CL-USER> (defmacro baz ()
(let ((*foo* 42))
(macroexpand '(bar))))
BAZ
CL-USER> (baz)
foo: 42
2
But, if you're going to do macroexpansion yourself, be sure to preserve environment arguments. In this case, a better definition of baz would be:
(defmacro baz (&environment env)
(let ((*foo* 42))
(macroexpand '(bar) env)))
Be gentle, as my macrofoo is weak.
What I'd like to do is something like this:
(defmacro foo [x] `(dosync (alter x# conj x)))
(defmacro bar [] `(let [x# (ref [])] (foo 3)))
Is this possible? I can't just (let [x ..] ..) because of symbol capturing.
NOTE: I'm aware this example is trivial and not macro-worthy, but it's the simplest example I could come up with.
I needed to force symbol capturing.
(defmacro foo [x] `(dosync (alter ~'x conj x)))
(defmacro bar [] `(let [~'x (ref [])] (foo 3)))
Although dangerous if you don't understand macros thoroughly, this works.
Dear all, I now have a preliminary macro
(defmacro key-if(test &key then else)
`(cond (,test
,then)
(t,else)))
and it is now correctly working as
> (key-if (> 3 1) :then 'ok)
OK
> (key-if (< 5 3) :else 'ok)
OK
> (key-if (> 3 1) :else 'oops)
NIL
> (key-if (> 3 1) :else 'oops :then 'ok)
OK
Now I want to extend it a bit, which means I want to have arbitrary number of arguments followed by :then or :else (the keyword), so it will work like
> (key-if (> 3 1) :then)
NIL
> (key-if (> 3 1) :else 'oops :then (print 'hi) 'ok)
HI
OK
so I am now stuck on this point, I am a bit new to Lisp macros. I could think of using &rest for this extension, but don't know how, so I really need your idea on how to get this extension to work.
Thanks a lot.
I assume that you are using some Common Lisp implementation.
That style of argument parsing is not directly supported by the standard lambda lists used by DEFMACRO. You are right in thinking that you will have to parse the arguments yourself (you could use (test &rest keys-and-forms) to capture TEST, but extracting the :ELSE and :THEN parts would be up to you.
I am no super-(Common-)Lisper, but the syntax you are inventing here seems very non-idiomatic. The first hint is that macro lambda lists do not support what you want. Also, there are already standard alternatives that are the same length or shorter in raw characters typed (the typing overhead can be reduced a bit by using a structure editor like paredit in an Emacs).
(key-if blah :then foo bar) ; multiple then, no else
(when blah foo bar) ; standard
(key-if blah :else baz quux) ; no then, multiple else
(unless blah baz quux) ; standard
(key-if blah :then foo :else baz quux) ; one then, multiple else
(if blah foo (progn baz quux)) ; standard
(cond (blah foo) (t baz quux))
(key-if blah :then foo bar :else baz) ; multiple then, one else
(if blah (progn foo bar) baz) ; standard
(cond (blah foo bar) (t baz))
(key-if blah :then foo bar :else baz quux) ; multiple then, multiple else
(if blah (progn foo bar) (progn baz quux)) ; standard
(cond (blah foo bar) (t baz quux)) ; even shorter
(key-if blah :else baz quux :then foo bar) ; multiple else before multiple then
(if (not blah) (progn baz quux) (progn foo bar)) ; only standard variation that is longer
(cond ((not blah) baz quux) (t foo bar) ; standard, shorter
Common Lisp macros are very powerful code templating engines, but this particular usage makes me think that you are just not quite comfortable with the standard styles and idioms in Common Lisp. No matter which language you are using, it is almost always a good idea to “go with the flow” by adopting the ‘local’ styles and idioms instead of bringing styles and idioms from other languages with which you are more familiar.
The &KEY mechanism only works on pairs. So you only have two paths: continue using pairs (you may use lists for the then and else arguments, and put these lists into PROGNs), or do you own parser on &REST.
Here is a parser on &REST:
(defmacro keyif (test &rest rest)
(loop with then? = t
for arg in rest
if (eq arg :then) do (setf then? t)
else if (eq arg :else) do (setf then? nil)
else if then? collect arg into then-list
else collect arg into else-list
finally (return `(if ,test (progn ,#then-list) (progn ,#else-list)))))
It loops on the rest list, collecting the args into either then-list or else-list, depending on the then? flag, which is changed when the keywords :then and :else are found. As a bonus, multiple then/else keywords are supported, and :then is assumed by default.