After understanding (quote), I'm curious as to how one might cause the statement to execute. My first thought was
(defvar x '(+ 2 21))
`(,#x)
but that just evaluates to (+ 2 21), or the contents of x. How would one run code that was placed in a list?
(eval '(+ 2 21))
#Christián Romo:
Backtick example: you can kinda implement apply using eval and backtick, because you can splice arguments into a form. Not going to be the most efficient thing in the world, but:
(eval `(and ,#(loop for x from 1 upto 4 collect `(evenp ,x))))
is equivalent to
(eval '(and (evenp 1) (evenp 2) (evenp 3) (evenp 4)))
Incidentally, this has the same result as the (much more efficient)
(every 'evenp '(1 2 3 4))
Hope that satisfies your curiosity!
Take a look at funny Lisp tutorial at http://lisperati.com/. There are versions for Common Lisp and Emacs Lisp, and it demonstrates use of quasiquote and macros.
Related
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?)
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
Background: I was working on a project in guile 1.8.8 scheme a few weeks ago and, being a little rusty, I forgot about the built-in (reduce) function, so I rolled my own. A little later, I ran into what seemed to be a hopeless bug, where calling a function with no side effects changed the flow of the rest of the program (working properly and passing a few unit tests vs. crashing completely) AFTER the function had long since returned. Several pieces of code which used to return something like (A B C D) were now returning only (A), causing a multitude of problems.
Minimum working example: After several days of whittling, I cornered the problem into this small piece of stand-alone code:
(define (my-reduce fun ls)
(if (null? (cdr ls))
(car ls)
(my-reduce fun (cons (fun (car ls) (cadr ls))
(cddr ls)))))
(format #t "~a " (my-reduce + '(1 2 3)))
(format #t "~a " (my-reduce or '(1 2 3)))
(format #t "~a~%" (my-reduce + '(1 2 3)))
Which prints out 6 1 1, instead of the expected 6 1 6.
Additional observations:
Setting the second line to a + yields the expected 6 6 6.
Setting the second line to and yields 6 3 3.
Additional lines of + after these produce additional 1s or 3s depending on what the second line is set to. So, the sequence + or + + leads to the output 6 1 1 1.
Additional lines of and or or after the first do NOT switch the output back. So, if the sequence is + and or +, the output is 6 3 3 3. It seems as though, once I've passed or or and to (my-reduce), the function becomes permanently "stuck" having that as its argument.
I also notice that passing and or or to the built-in (reduce) function causes a type-error, since they are technically macros and not functions.
Along those same lines, I notice that swapping out or for (lambda (x y) (or x y)) yields the expected output. Therefore, it seems that the critical thing here is that passing macros to my home-rolled reduce function causes an issue.
Question: What is going on here? Why does calling (my-reduce) with and or or cause such unexpected behavior? Does it have to do with the fact that those "functions" are actually macros?
Thanks in advance for any help. This one has really stumped me!
You said it yourself, you can't pass and, or as parameters where a function is expected because they're macros, and will complain with a "bad syntax" error. In fact, I can't understand how this even works for you:
(my-reduce or '(1 2 3))
The only way I can think of is that you redefined and, or as functions somewhere, and that is the source of the problems. As a side note, my-reduce (understood as a fold-right operation) can be implemented in a more standard way like this:
(define (my-reduce fun ls)
(if (null? (cdr ls))
(car ls)
(fun (car ls)
(my-reduce fun (cdr ls)))))
The above assumes that the list is non-empty, if that's not always the case, the usual is to pass as parameter an initial value:
(define (my-reduce fun init ls)
(if (null? ls)
init
(fun (car ls)
(my-reduce fun init (cdr ls)))))
I'm just starting out with LISP, as in, just opened the book, I'm two pages into it. I'm trying to understand what is and what is not an acceptable fn call. Every time I try to execute
(1 2 3 4)
I get an illegal fn call error
same goes for
(cdr (1 2 3 4))
(first (1 2 3 4))
(a b c d)
Are CL programs unable to return lists? How would I go about using these functions or printing a list? I'm using the SLIME implementation if it matters. LISP is very different than anything I've worked with before and I want to be sure I'm getting it conceptually.
You need to quote lists if you are using them as constants. Otherwise, the system will try to call the function 1 on the arguments 2 3 4, which will not work (note that function calls have the same syntax as lists). Your examples should be:
'(1 2 3 4)
(cdr '(1 2 3 4))
(first '(1 2 3 4))
'(a b c d)
Hooo boy.
Look up Practical Common Lisp by Seibel. He's such a nice guy, he put it online for free reading. It's very useful.
Part of the definition of Lisp is this rule:
When a list is seen: Using the first element of the list, apply it to the rest of the list.
But wait: How do you actually enter lists then? There are two functions to do this: QUOTE and LIST.
As an example, let's print a list to the screen on standard out:
(format *standard-output* "~a" '(1 2 3 4))
For format, *standard-output* is aliased to t (well, at least in SBCL!), so usually we see (format t ....
I've been slowly working my way though the exercises in Structure and Interpretation of Computer Programs. Section 1.1.5 talks about applicative vs. normal-order evaluation, and the topic has come up several times in the text afterward. Since the interpreter uses applicative-order evaluation, it's easy to just insert display debug statements in your code to see exactly how it works. It would help my understanding to be able to do the same thing for normal-order evaluation.
Does anyone know of a Scheme (or Lisp) interpreter that's implemented using normal-order evaluation instead of applicative-order?
Update:
Here's a short example modified from the one given in SICP. I'll define my own add procedure to print out the arguments, and use the square procedure from the book.
(define (add x y)
(display x)
(display y)
(newline)
(+ x y))
(define (square x) (* x x))
Now if I run the short program (square (add 1 2)) using applicative-order evaluation, the result of (add 1 2) will only be computed once then passed to the square procedure. The operands 12 should be printed once before the final result. We can just run this in an interpreter to verify that this is what happens.
> (square (add 1 2))
12
9
Using normal-order evaluation, though, the single operand (add 1 2) should be copied into the square procedure, which would evaluate as (* (add 1 2) (add 1 2)). The operands 12 should be printed twice before the final result.
I'd like to be able to run this in an interpreter that does normal-order evaluation to verify that this is indeed how it works.
Turns out Scheme actually comes with what is essentially a normal-order evaluator already. They're those fabled macros you've probably heard so much about, and we can rewrite the examples of sections 1.1.4--1.1.5 to use macro expansion in lieu of procedure application rather easily:
(define (print . items)
(for-each display items))
(define-macro (add x y)
`(begin (print "[ADD " ',x " " ',y "]")
(+ ,x ,y)))
(define-macro (mul x y)
`(begin (print "[MUL " ',x " " ',y "]")
(* ,x ,y)))
(define-macro (square x)
`(begin (print "[SQUARE " ',x "]")
(mul ,x ,x)))
(define-macro (sum-of-squares x y)
`(begin (print "[SUM-OF-SQUARES " ',x " " ',y "]")
(add (square ,x) (square ,y))))
(define-macro (f a)
`(begin (print "[F " ',a "]")
(sum-of-squares (add ,a 1) (mul ,a 2))))
Ignore the PRINTs, their logic is a little beyond where you're at in the text, but they're just a shorthand for lots of DISPLAYs. Actually, you would want to entirely forgo the tracing-by-printing in favor of using the system's macro-expansion function. but this varies with the implementation (e.g. in Ypsilon you would use (macro-expand '(f 5))).
If you load these definitions (with the caveat that DEFINE-MACRO is non-standard, but that shouldn't be a problem in practice since most Schemes provide it), then evaluating (f 5) like the book does will print out (of course I prettied it up a little):
[F 5]
[SUM-OF-SQUARES (add 5 1) (mul 5 2)]
[ADD (square (add 5 1)) (square (mul 5 2))]
[SQUARE (add 5 1)]
[MUL (add 5 1) (add 5 1)]
[ADD 5 1]
[ADD 5 1]
[SQUARE (mul 5 2)]
[MUL (mul 5 2) (mul 5 2)]
[MUL 5 2]
[MUL 5 2]
136
Which is more or less what the book illustrates the process should be.
Writing these sorts of macros is basically like writing a normal procedure, except that
Instead of DEFINE, you use DEFINE-MACRO.
There is no implicit BEGIN over the body, so you need to supply your own if you have multiple expressions.
The entire body expression is prefixed with a grave accent.
All instances of the parameters are prefixed with a comma.
That's Writing Scheme Macros 101.
Now all in all, this is a little silly to spring macros on someone on just the first chapter of SICP. But if you say you're having an inordinate amount of difficulty modifying Racket to do what you want (and then there are those not using Racket at all), then here's an alternative.
Racket has a lazy language. It's better than just an interpreter, since you can write programs that are made of plain racket modules and lazy ones.
As for debugging using printouts -- you can do that in this lazy language, and you get something similar to unsafe IO in Haskell. This can still be confusing sometimes though. (And if you wanted an interpreter to plug printouts into it, it would also be confusing, because it follows the lazy evaluation...)