1

I am new to Lisp and I am trying to understand how variables and assigning variables work. I am trying to check if a given number is 5 or not. If it is, it is supposed to change it to 10 and print it. If not it just tells you that it is not 5 but my code below is not working.

(print "Give me a number")
(setq *x* (read))

(defun check(*x*)
    (if (= *x* 5) (setq *x* 10) (format t "~d is not 5" *x*))
)

check(*x*)
print(*x*)


2 Answers 2

2
  • check(*x*) and print(*x*) isn't Lisp syntax. Replace that with (check *x*) and (print *x*)
  • Your function operates with some *x*, but it isn't your global *x*, but local variable*x* from argument list. Don't name function arguments same as global variables. Check this example:
(defparameter a 8)
(defun add (a)
  (setf a (+ a 2))
  (print a))
(add a)
(print a)

Returned values are 10 and then 8. Compare it with:

(defparameter *a* 8)
(defun add (a)
  (setf *a* (+ *a* 2))
  (print *a*))
(add *a*)
(print *a*)

Returned values are 10 and 10.

  • Don't use setf or setq for creating variable, these functions are only for setting new value. Use defparameter or defvar instead.
  • This code assigns value to global variable:
(print "Give me a number")
(defparameter *x* (read *query-io*))
(defun check ()
  (if (= *x* 5)
      (setf *x* 10)
    (format t "~d is not 5" *x*)))
(check)
(print *x*)
  • You can also do this task without global variables.
(print "Give me a number")
(defun check (n)
  (if (= n 5)
      (setf n 10) 
    (format t "~d is not 5" n)) 
  (print n))
(check (read *query-io*))
Sign up to request clarification or add additional context in comments.

Comments

1

If I compile a file with this definition in SBCL:

(print "Give me a number")
(setq *x* (read))

(defun check(*x*)
    (if (= *x* 5) (setq *x* 10) (format t "~d is not 5" *x*))
)

There are two warnings:

warning: undefined variable: *X*

This is located at the global setq, because setq does not declare global variables. So the compiler does not know any global variable named *x*.

Then, inside the function:

style-warning:
 using the lexical binding of the symbol (*X*), not the
 dynamic binding, even though the name follows
 the usual naming convention (names like *FOO*) for special variables
 --> PROGN SB-IMPL::%DEFUN SB-IMPL::%DEFUN SB-INT:NAMED-LAMBDA
 ==>
   #'(SB-INT:NAMED-LAMBDA AAAB::CHECK
         (*X*)
       (DECLARE (SB-C::TOP-LEVEL-FORM))
       (BLOCK CHECK
         (IF (= *X* 5)
             (SETQ *X* 10)
             (FORMAT T "~d is not 5" *X*))))

This is pretty self-explanatory, but here the binding is lexical.

This is however not a property of defun, this is because there is no declared special variable named *x*.

If instead, you use defvar or defparameter, there is no warning (e.g. (defvar *x* 0)). The same goes if you only declare the variable as special: (declaim (special *x*)), before you define the function that binds it.

Inside the function, assuming *x* is declared as a special variable, the bindings works as a let, which means you can use special variables as function parameters. In your case this does not change much because you only set the current binding with the inner setq (the parameter shadows the global binding), so in effect this is a lot like a lexical variable.

But you can use a special variable to rebind dynamically a parameter:

(defun foo (*a*) ...)

This is the same as:

(defun foo (a)
  (let ((*a* a))
     ...))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.