Lisp SBCL macro quoted list as parameter - macros

Say I have a macro like
(defmacro repeat (times &body body)
(let ((x (gensym)))
`(dotimes (,x ,times)
,#body)))
Then I can run on the repl
CL-USER> (repeat 2 (print "Hi"))
"Hi"
"Hi"
NIL
If I run
CL-USER> (list 'print "Hi")
(PRINT "Hi")
So why can't I run
CL-USER> (repeat 2 (list 'print "hi"))
NIL
The backquote just gives me a list doesn't it? Is that not the same as what gets passed to the body parameter when I do not use a backquote (a list of s-expressions)?

Your code works fine, it just doesn't do what you think it should.
(repeat 2 (print "Hi")) evaluates its second argument twice, so it prints "Hi" two times. It also returns "Hi" twice, but dolist, and, thus, repeat, discards the return value of print.
(repeat 2 (list 'print "hi")) evaluates its second argument twice, so it creates the list (print "hi") twice and discards it. To have it actually print "hi", you would have to evaluate it two times (once producing code (print "hi") the the second time evaluating the code to print "hi").

Related

What is the difference between #\ , ' and #'?

In Common Lisp, given that "a" is simply a character, what is the difference between #\a, 'a #'a?
My question comes from the tutorialspoint.com tutorial on Lisp. At one point the tutorial introduces:
; a character array with all initial elements set to a
; is a string actually
(write(make-array 10 :element-type 'character :initial-element #\a))
(terpri)
; a two dimensional array with initial values a
(setq myarray (make-array '(2 2) :initial-element 'a :adjustable t))
(write myarray)
(terpri)
With the output:
"aaaaaaaaaa"
#2A((A A) (A A))
#' is not included in this example but I'm including it in the question because it can be confusing as well. 🙂
Thank you very much! 😊
To start, a is not "simply a character." The Lisp reader parses #\a as the character literal a, which is an object in Common Lisp. Note that #\a and #\A are different character objects.
When the Lisp reader encounters a single quote, the expression following the single quote is not evaluated. Specifically, 'a is treated as (quote a), where quote returns its argument unevaluated. Now, a is a symbol, so 'a evaluates to that symbol. But the Lisp reader upcases most characters it reads by default, so 'a really evaluates to the symbol A. The good news is that whether you type a or A, the Lisp reader will read A (unless you mess with the readtable), and both 'a and 'A evaluate to the symbol A.
When the Lisp reader encounters #'a, the entire expression is treated as (function a), which when evaluated returns the function associated with the name a. But, note that it is an error to use function, and by extension #', on an identifier that does not denote a function.
To clarify this last part a bit, consider the following REPL interaction:
CL-USER> (defvar a 1)
A
CL-USER> a
1
CL-USER> #'a
The function COMMON-LISP-USER::A is undefined.
[Condition of type UNDEFINED-FUNCTION]
Here the variable a is defined and given the value 1, but when we try to access the function denoted by a we get an error message because there is no such function. Continuing:
; Evaluation aborted on #<UNDEFINED-FUNCTION A {1002DDC303}>.
CL-USER> (defun a (x) x)
A
CL-USER> (a 'b)
B
CL-USER> a
1
CL-USER> #'a
#<FUNCTION A>
Now we have defined a function named a that simply returns its argument. You can see that when we call a with an argument 'b we get the expected result: (a 'b) --> b. But, then when we evaluate a alone we still get 1. Symbols in Common Lisp are objects that have, among other cells, value cells and function cells. After the above interaction, the symbol a now has 1 in its value cell, and it has the function we have defined in its function cell. When the symbol a is evaluated the value cell is accessed, but when (function a) or #'a is evaluated, the function cell is accessed. You can see above that when #'a is evaluated, the function we defined is returned, and the REPL prints #<FUNCTION A> to show this.
As an aside, I wouldn't recommend using Tutorialspoint to learn Common Lisp. Glancing over the site, right away I see this:
LISP expressions are case-insensitive, cos 45 or COS 45 are same.
This is just wrong. And, Lisp is not written in all-caps. None of this inspires faith. Instead, find a good book. There are some recommendations on the common-lisp tag-info page.
#\
This is to introduce a character.
CL-USER> #\a
#\a
CL-USER> (character 'a)
#\A
CL-USER> (character "a")
#\a
'
This is quote, to quote and not evaluate things and construct object literals.
CL-USER> a
=> error: the variable a is unbound.
CL-USER> 'a
A
CL-USER> (inspect 'a)
The object is a SYMBOL.
0. Name: "A"
1. Package: #<PACKAGE "COMMON-LISP-USER">
2. Value: "unbound"
3. Function: "unbound"
4. Plist: NIL
> q
CL-USER> (equal (list 1 2) (quote (1 2))) ;; aka '(1 2)
T ;; but watch out with object literals constructed with quote, prefer constructor functions.
and #'
This is sharpsign-quote to reference a function.
CL-USER> #'a
=> error: The function COMMON-LISP-USER::A is undefined.
CL-USER> (defun a () (print "hello A"))
A
CL-USER> (a)
"hello A"
"hello A"
CL-USER> #'a
#<FUNCTION A>
CL-USER> (function a)
#<FUNCTION A>
One can ask Lisp to describe the data objects you've mentioned.
If we look at the expressions:
CL-USER 13 > (dolist (object (list '#\a ''a '#'a))
(terpri)
(describe object)
(terpri))
#\a is a CHARACTER
Name "Latin-Small-Letter-A"
Code 97
(QUOTE A) is a LIST
0 QUOTE
1 A
(FUNCTION A) is a LIST
0 FUNCTION
1 A
NIL
If we look at the evaluated expressions:
CL-USER 5 > (dolist (object (list #\a 'a #'a))
(terpri)
(describe object)
(terpri))
#\a is a CHARACTER
Name "Latin-Small-Letter-A"
Code 97
A is a SYMBOL
NAME "A"
VALUE #<unbound value>
FUNCTION #<interpreted function A 422005BD54>
PLIST NIL
PACKAGE #<The COMMON-LISP-USER package, 73/256 internal, 0/4 external>
#<interpreted function A 422005BD54> is a TYPE::INTERPRETED-FUNCTION
CODE (LAMBDA (B)
A)

Common LIsp issue with Macros and variables

I have an assignment where I need to write a script using lisp. I am having issues with passing variables
Here is the code. Issues to follow:
(defmacro while (test &rest bodies)
`(do ()
((not ,test))
,# bodies)
)
(defmacro += (var inc)
`(print (eval var))
;(setf (eval var) (+ (eval var) inc))
)
(defmacro iterate (i begin end inc &rest others)
(setf i begin)
(while (<= i (eval end))
;(dolist (item others)
; (eval item)
;)
(print (list 'two i (eval end)))
(+= (eval end) 1)
(setf i (+ i inc))
)
)
(setf n 5)
(iterate i 1 n 1
(print (list 'one i))
(+= n 1)
)
The first issue lies in passing the statements to the iterate macro. When I try to run the commented out dolist, the print statement will throw an error when it comes to the variable i. For some reason I can not get it to print using the macro variable i which has a value, but it seems to want to default to the global variable i which has not been set. I get the error:
- EVAL: variable I has no value
The second issue is when I call the "+=" macro. The value of end in the iterate macro is 5 as passed to the macro by use of the variable N which it is set to 5, however, when I pass it to the "+=" macro using the line "(+= (eval end) 1)" I can not get it to pass the value. I tried removing the eval in the line "(+= (eval end) 1)" and when I try printing it with "(print (eval var))" in the "+=" macro, I get the error
- EVAL: variable END has no value
How would I solve these issues?
Your first macro is basically correct. It generates code.
(defmacro while (test &body body)
`(do ()
((not ,test))
,#body))
One can check it with an example. We expand the macro using example code. The function MACROEXPAND-1 expands the top-level macro exactly once. You need to pass code to the function MACROEXPAND-1:
CL-USER 1 > (macroexpand-1 '(while (< i 10)
(print i)
(incf i)))
(DO NIL ; NIL is the same as ()
((NOT (< I 10)))
(PRINT I)
(INCF I))
T
The generated code is a DO loop. Just like intended.
Thus we can use your macro:
CL-USER 2 > (let ((i 5))
(while (< i 10)
(print i)
(incf i)))
5
6
7
8
9
NIL
Your other macros should be like that
they should generate code
macro expansion of examples should show the right generated code
the generated code should work
Your macros should NOT
be using EVAL
try to compute results other than code

Lisp function returns NIL when used in a menu function but otherwise works

I wrote a function to query a small database program I'm writing for school. This function searches by name. When I run the function by itself it works. When I run it within the menu it does not work (it returns NIL).
Here is everything relevant:
(defun prompt-read (prompt)
(format *query-io* "~a: " prompt)
(force-output *query-io*)
(read-line *query-io*))
(defun search-name (name)
(remove-if-not
#'(lambda (cat) (equal (getf cat :name) name)) *db*))
(defun input-name ()
(search-name
(prompt-read "Name")))
(defun search-menu ()
(print "1) Search Name")
(print "2) Search Color")
(print "3) Search Min. Weight")
(print "4) Search Min. Experience")
(print "5) Search Min. Length")
(setf choose (read))
(cond ((= choose 1)(input-name))
((= choose 2)(print "Color"))
((= choose 3)(print "Weight"))
((= choose 4)(print "XP"))
((= choose 5)(print "Color"))
)
NIL
)
Right now I am only working on getting the name search working, the rest of the menu is just placeholders. When I run "input-name" (which uses search-name) by itself it returns the correct result. When I try the first option from the search-menu (which also runs "input-name") it returns NIL. I am wondering why when I run it by itself works but not when used with that menu. If anybody needs any other information feel free to ask. I will try my best to provide it. Also, I am a beginner so please forgive me.
If you want output in a program, then you need to print something.
(defun example ()
1000)
The above function prints nothing. It just returns a number.
If we call it in the read-eval-print-loop:
CL-USER 134 > (defun example ()
1000)
EXAMPLE
CL-USER 135 > (example)
1000
You see that 1000 gets printed. But why?
We run it in the READ-EVAL-PRINT-LOOP. The read, eval, PRINT, loop.
Means: the Lisp system is printing the returned value of the evaluation, but not your code.
Now we add a print call:
CL-USER 136 > (defun example ()
(print 1000))
EXAMPLE
CL-USER 137 > (example)
1000
1000
It's printed twice!
CL-USER 137 > (example)
1000 ; <- the function example prints
1000 ; <- the read-eval-print-loop prints the result
So our function now prints something itself, since it calls PRINT.
Now this works:
CL-USER 138 > (defun call-the-example ()
(example)
(values))
CALL-THE-EXAMPLE
CL-USER 139 > (call-the-example)
1000
We can call the example function, the function prints something, and the REPL prints nothing.
The REPL prints nothing, since call-the-example returns nothing. It returns no value.
Thus you need to add a PRINT call
You are right to add a print call, but the reason is simply that before you did not print and the call to (input-name) did not print. You were calling (input-name) in the READ-EVAL-PRINT-LOOP, which then prints the result. Not your code, but the REPL did output.
Style: undefined variable
(defun foo ()
(setf bar 10) ; <- BAR is undefined
(print bar) ; <- BAR is undefined
(setf bar 20) ; <- BAR is undefined
(print bar)) ; <- BAR is undefined
Write this instead - using LET to define a local variable:
(defun foo ()
(let ((bar 10)) ; define BAR
(print bar) ; BAR is defined
(setf bar 20) ; BAR is defined
(print bar))) ; BAR is defined
search-menu doesn't do anything with the return value from input-name. A function returns the value of the last expression that it executes, and the last expression in search-menu is NIL, so that's what it returns.
If you want it to return the value of the cond expression, remove NIL from the end.
You should also use let to declare a local variable, rather than assigning the undefined variable choose.
(defun search-menu ()
(print "1) Search Name")
(print "2) Search Color")
(print "3) Search Min. Weight")
(print "4) Search Min. Experience")
(print "5) Search Min. Length")
(let ((choose (read)))
(cond ((= choose 1) (input-name))
((= choose 2) (print "Color"))
((= choose 3) (print "Weight"))
((= choose 4) (print "XP"))
((= choose 5) (print "Color")))))
I ended up finding a solution that works by simply using print in the input-name function. This function only has to show results so this works just fine.
(defun input-name ()
(print
(search-name
(prompt-read "Name"))))
Same function as before but with an added print. Now it also works in the menu.

Unbound variable error when using defmacro in LISP

I am trying to use macro with two forms in LISP, which evaluates both forms but always return the result of form 2. Below is the code that I am using -
(defmacro testmac (x body) (prog2 x body))
When executing the macro with following forms, It works correctly and always return 5 which is the second form.
(testmac (- 10 6) (/ 10 2))
However when I try to execute macro with following forms, its return error.
(testmac (print a) (print b))
Below is the error I get -
debugger invoked on a UNBOUND-VARIABLE: The variable B is unbound.
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-INT:SIMPLE-EVAL-IN-LEXENV B #<NULL-LEXENV>)
Why am I getting this error and how can I use macro to make this work?
P.S. I cannot use defun need to use macro to execute (testmac (print a) (print b))
I am trying to use macro with two forms in LISP, which evaluates both forms but always return the result of form 2.
That's usually not a good idea - though it might be just not precise wording. A macro should not evaluate code - not without a good reason. Usually the macro just transforms code. The generated code then decides what to evaluate.
(defmacro testmac (x body) (prog2 x body))
(testmac (- 10 6) (/ 10 2))
So x is the list (- 10 6) and body is the list (/ 10 2).
Your macro returns the second list.
CL-USER 11 > (macroexpand-1 '(testmac (print a) (print b)))
(PRINT B)
The macro returns the form (print b). It then gets executed.
CL-USER 12 > (testmac (print a) (print b))
Error: The variable B is unbound.
If B is undefined you get the error you see.
There is no magic going on.
That's because your testmac macro directly executes (prog2 x body), instead of expanding into it.
You need to write it like this:
(defmacro testmac (x body)
`(prog2 ,x ,body))
The form after the backquote won't be evaluated, but those after a comma will.
You can (and you should!) test the expansion like this:
(macroexpand-1 '(testmac (print 42) (print 51)))
Which gives:
(PROG2 (PRINT 42) (PRINT 51))

Behaviour of special variables under macro expansion

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)))