I wrote this macro that rewrites e.g. (sum-expr (1 2 3)) as (+ 1 2 3):
(defmacro sum-expr (expr-list)
`(+ ,#expr-list))
=> SUM-EXPR
For example:
(sum-expr ((+ 1 3) (* 3 4) (- 8 4)))
=> 20
How can I define an equivalent function using defun?
As #LeonardoDagnino already mentioned it in comment:
(defun sum-expr (lst)
(apply #'+ lst))
Would be very lispy, but implementation-dependent CALL-ARGUMENTS-LIMIT limits in some implementations the length of lst to 50 as discussed e.g. here .Therefore, the solution with reduce is cleaner.
Sounds like you need to evaluate the expressions in your list, and then reduce the resulting list by the addition function.
We can evaluate lisp expressions with eval, which we can apply to each element of the input list with mapcar.
We can then use reduce on the resulting list to find the sum.
(defun sum-expr (list)
(reduce #'+ (mapcar #'eval list)))
This makes a lot of assumptions about the structure and type of your input, but for a simple problem with well-understood inputs, it should be fine.
(You may be interested in Why exactly is eval evil?)
Related
I am going through a lisp book and I am looking at mapcar, my question is why is that this is valid:
> (mapcar #'+ '(1 2) '(3 4))
but this one isn't:
(mapcar + '(1 2) '(3 4))
in other words, is there a reason it was decided in lisp that the first argument to mapcar cannot be the function itself, and has to be its name? what purpose does this serve?
is there a reason it was decided in lisp that the first argument to mapcar cannot be the function itself, and has to be its name? what purpose does this serve?
It's just that in something like Common Lisp, the identifier + has multiple different purposes. It is a variable, a function, plus various other things.
writing + means the variable. It is used by the read eval print loop. The value of + is the last form that was evaluated, the value of ++ is the previous value of +, and the value of +++ is the previous value of ++.
To tell Common Lisp that you want to use the function value of an identifier +, one has to write (function +) or shorter #'+.
Thus
(mapcar (function +) '(1 2) '(3 4))
or shorter
(mapcar #'+ '(1 2) '(3 4))
actually means call mapcar with the function + and the lists (1 2) and (3 4)
There are two other ways to use the function +.
(mapcar '+ '(1 2) '(3 4))
Above will have Lisp retrieve the global function value of the symbol +.
Fourth, we can also have the function object be a part of the source code.
#'+ is a function. Common Lisp is what's called a 'lisp 2', which means that it has two namespaces: during evaluation of a compound form, like (+ a b), the function position is looked up in the function namespace while the other positions are looked up in the value namespace. This means that, for instance (append list list) does not make a list whose two elements are the list function: it makes a list whose two elements are whatever list happens to be bound to as a value.
But sometimes you need to get the function value of a name in a value position: an example is in the first argument of mapcar. To do that there is a special operator, function: (mapcar (function +) x y) adds the elements of two lists. Like quote, function has a read macro, which is #'.
(To make this more fun, mapcar actually expects a function designator so you can use the nsme of a function: (mapcar '+ x y) will work, although it is a bit horrid.)
I’m trying to get get my macro to do an extra evaluation of its result before returning it. Can this be done without eval?
I'm trying to solve the problem in exercise 4 below:
Define a macro nth-expr that takes an integer n and an arbitrary number of expressions, evaluates the nth expression and returns its value. This exercise is easy to solve, if you assume that the first argument is a literal integer.
4. As exercise 3, but assume that the first argument is an expression to be evaluated.
It's easy to get the macro to pick the right expression:
(defmacro nth-expr% (n &rest es)
`(nth ,n ',es))
CL-USER> (defvar i 1)
I
CL-USER> (nth-expr% (1+ i) (+ 2 3) (- 4 3) (+ 3 1))
(+ 3 1)
The expression (+ 3 1) is the one we want, but we want the macro to evaluate it to 4 before returning it.
It can of course be done with eval:
(defmacro nth-expr%% (n &rest es)
`(eval (nth ,n ',es)))
CL-USER> (nth-expr%% (1+ i) (+ 2 3) (- 4 3) (+ 3 1))
4
But is there another way?
It feels like the solution should be to put the body of nth-expr% in a helper macro and have the top level macro only contain an unquoted call to this helper:
(defmacro helper (n es)
`(nth ,n ',es))
(defmacro nth-expr (n &rest es) ; doesn't work!
(helper n es))
The idea is that the call to helper would return (+ 3 1), and this would then be the expansion of the call to nth-expr, which at run-time would evaluate to 4. It blows up, of course, because N and ES get treated like literals.
That's not that easy.
Using eval is not good, since eval does not evaluate the code in the local lexical environment.
Remember, if we allow an expression to be evaluated to determine the number of another expression to execute, then we don't know this number at macro expansion time - since the expression could be based on a value that needs to be computed - for example based on some variable:
(nth-expression
foo
(bar)
(baz))
So we might want to think about code which does that:
(case foo
(0 (bar))
(1 (baz)))
CASE is evaluating foo and then uses the result to find a clause which has the same value in its head. The consequent forms of that clause then will be evaluated.
Now we need to write code which expands the former into the latter.
This would be a very simple version:
(defmacro nth-expression (n-form &body expressions)
`(case ,n-form
,#(loop for e in expressions
and i from 0
collect `(,i ,e))))
Question: what might be drawbacks of using CASE like that?
Knuto: Rainer Joswig may be asking you to think about how the case statement works. Namely, that after evaluating the keyform (ie, the first argument), it will be compared sequentially to the key in each clause until a match is found. The comparisons could be time consuming if there are many clauses. You can discover this by carefully reading the entry for case in the Hyperspec (as he more than once has insisted I do):
The keyform or keyplace is evaluated to produce the test-key. Each of
the normal-clauses is then considered in turn.
Also note that constructing many case clauses will add to the time to expand and compile the macro at compile time.
Regarding your use of eval in nth-expr%%, you can still achieve the effect of an eval by switching to apply:
(defmacro nth-expr%% (n &rest es)
`(let ((ne (nth ,n ',es)))
(apply (car ne) (cdr ne))))
But see Plugging the Leaks at http://www.gigamonkeys.com/book/macros-defining-your-own.html about a more robust treatment.
In general, a more efficient way to process the expressions is as a simple vector, rather than a list. (The problem statement does not rule out a vector representation.) While nth and case involve searching through the expressions one-by-one, a function like aref or svref can directly index into it. Assuming a vector of expressions is passed to the macro along with an index, perhaps first requiring (coerce expressions 'simple-vector) if a list, then the result can be computed in constant time no matter how many expressions there are:
(defmacro nth-expr%%% (n es)
`(let ((ne (svref ',es ,n)))
(apply (car ne) (cdr ne))))
so that now
(defvar i 1)
(nth-expr%%% (1+ i) #((+ 2 3) (- 4 3) (+ 3 1))) -> 4
I would like to generate code: (nth 0 x) (nth 1 x) ... (nth n x)
where x is just some variable name, and n is some number.
I'm trying do this in a following way:
(defmacro gen(n)
(loop for i from 1 to n do
`(nth i x))
)
Checking how it expands by:
(print (macroexpand-1 '(gen 5)))
Console output is: NIL. How to do it properly?
You need to replace do with collect in your loop.
Note however that your macro captures the variable x from the calling environment.
Generally speaking, "macros are advanced material", if you are not comfortable with loop, you probably should not be writing them.
Consider what the value of the following code is:
(loop for i from 1 to 5
do `(nth ,i x))
Since there's no collection happening, the return value of the loop is nil. If we change do to collect:
(loop for i from 1 to 5
collect `(nth ,i x))
We see that we are getting somewhere. However, the resulting list is not actually valid Common Lisp code (and relies on there being a variable x in the environment where the macro is used).
It is not clear what you want to do with these (just run them? they're side-effect free, so just wrapping this in a progn feels somewhat useless), but you need to either cons a progn, list or similar to the front of the list of lists to make it into valid code.
(defmacro gen (n &key (var 'x) (accumulator 'list))
(cons accumulator
(loop for i from 1 to n
collect `(nth ,i ,var))))
This eventually gives us this macro that seems to actually do something approaching "valid".
I want to know if these two definitions of nth are equal:
I. is defined as macro:
(defmacro -nth (n lst)
(defun f (n1 lst1)
(cond ((eql n1 0) lst1)
(t `(cdr ,(f (- n1 1) lst1)))))
`(car ,(f n lst)))
II. is defined as a bunch of functions:
(defun f (n lst)
(cond ((eql n 0) lst)
(t `(cdr ,(f (- n 1) lst)))))
(defun f1 (n lst)
`(car ,(f n `',lst)))
(defun --nth (n lst)
(eval (f1 n lst)))
Am i get the right idea? Is macro definition is evaluating of expression, constructed in its body?
OK, let start from the beginning.
Macro is used to create new forms that usually depend on macro's input. Before code is complied or evaluated, macro has to be expanded. Expansion of a macro is a process that takes place before evaluation of form where it is used. Result of such expansion is usually a lisp form.
So inside a macro here are a several levels of code.
Not quoted code will be evaluated during macroexpansion (not at run-time!), in your example you define function f when macro is expanded (for what?);
Next here is quoted (with usual quote or backquote or even nested backquotes) code that will become part of macroexpansion result (in its literal form); you can control what part of code will be evaluated during macroexpansion and what will stay intact (quoted, partially or completely). This allows one to construct anything before it will be executed.
Another feature of macro is that it does not evaluate its parameters before expansion, while function does. To give you picture of what is a macro, see this (just first thing that came to mind):
(defmacro aif (test then &optional else)
`(let ((it ,test))
(if it ,then ,else)))
You can use it like this:
CL-USER> (defparameter *x* '((a . 1) (b . 2) (c . 3) (d . 4)))
*X*
CL-USER> (aif (find 'c *x* :key #'car) (1+ (cdr it)) 0)
4
This macro creates useful lexical binding, capturing variable it. After checking of a condition, you don't have to recalculate result, it's accessible in forms 'then' and 'else'. It's impossible to do with just a function, it has introduced new control construction in language. But macro is not just about creating lexical environments.
Macro is a powerful tool. It's impossible to fully describe what you can do with it, because you can do everything. But nth is not something you need a macro for. To construct a clone of nth you can try to write a recursive function.
It's important to note that LISP macro is most powerful thing in the programming world and LISP is the only language that has this power ;-)
To inspire you, I would recommend this article: http://www.paulgraham.com/avg.html
To master macro, begin with something like this:
http://www.gigamonkeys.com/book/macros-defining-your-own.html
Then may be Paul Graham's "On Lisp", then "Let Over Lambda".
There is no need for either a macro nor eval to make abstractions to get the nth element of a list. Your macro -nth doesn't even work unless the index is literal number. try this:
(defparameter test-list '(9 8 7 6 5 4 3 2 1 0))
(defparameter index 3)
(nth index test-list) ; ==> 6 (this is the LISP provided nth)
(-nth index test-list) ; ==> ERROR: index is not a number
A typical recursive solution of nth:
(defun nth2 (index list)
(if (<= index 0)
(car list)
(nth2 (1- index) (cdr list))))
(nth2 index test-list) ; ==> 6
A typical loop version
(defun nth3 (index list)
(loop :for e :in list
:for i :from index :downto 0
:when (= i 0) :return e))
(nth3 index test-list) ; ==> 6
Usually a macro is something you use when you see your are repeating yourself too much and there is no way to abstract your code further with functions. You may make a macro that saves you the time to write boilerplate code. Of course there is a trade off of not being standard code so you usually write the macro after a couple of times have written the boilerplate.
eval should never be used unless you really have to. Usually you can get by with funcall and apply. eval works only in the global scope so you loose closure variables.
I cannot think of a way to search a list to make sure it has all integers. I want to immediately return nil if there is non-integer data, and continue my function if there is not.
The recursive function I am trying to make will cons the car with the cdr of the list. With the attempts I have made, I am not able to return nil. I have only been able to ignore the non-integer data. E.g., (add-1-all '(1 2 3 a)) will return (2 3 4) after adding one to each number.
(defun add-1-all (L)
(if (null L)
L
(if (integerp (car L))
(cons (+ (car L) 1) (add-1-all (cdr L)))
nil)))
I do understand that the cons is making this happen, as the recursion is adding on to the list.
Your first sentence,
I cannot think of a way to search a list in Lisp to make sure it has all integers.
makes it sound like you want to check whether a list is all integers. You can check whether a list is all integers using every:
CL-USER> (every 'integerp '(1 2 3 4))
;=> T
CL-USER> (every 'integerp '(1 2 a 4))
;=> NIL
every will take care of short-circuiting, i.e., returning nil as soon as the first element failing the predicate is found.
However, your code makes it sound like you want to map over a list, collecting the value of a function applied to each integer and returning the collected values, except that if you encounter a non-integer, you return null. Perhaps the easiest way to do this is using the loop macro. A solution looks almost identical to the English specification:
CL-USER> (loop for x in '(1 2 3 4)
if (not (integerp x)) return nil
else collect (1+ x))
;=> (2 3 4 5)
CL-USER> (loop for x in '(1 2 a 4)
if (not (integerp x)) return nil
else collect (1+ x))
;=> NIL
Doing this with loop also has some advantages over a recursive solution. While some languages in the Lisp family (e.g., Schema) require tail call optimization, and some Common Lisp implementations do it too, it's not required in Common Lisp. As a result, it can be safer (e.g., you won't run out of stack space) if you use an iterative solution (e.g., with loop) rather than a recursive (even a tail-recursive) implementation.
The key is to use a helper function, and for that helper function to carry the answer along with it as it recurses, so that it can discard the whole thing at any time if necessary. Incidentally, this will also be tail recursive, meaning that it can deal with extremely long lists without running out of stack space.
(defun add-1-all (L)
(add-1-all-helper L nil))
(defun add-1-all-helper (L answer)
(if (null L)
answer
(if (integerp (car L))
(add-1-all-helper
(cdr L)
(cons (+ (car L) 1) answer)))))