Common lisp error , not binding variables - common-lisp

I am following Practical Common Lisp. I have followed the example to the tee. When I compile in Emacs C-c C-c I get the following error with this code.
(defun make-cd (title artist rating ripped)
(list :title title :artist artist :rating rating :ripped ripped))
(defvar *db* nil)
(defun add-record (cd)(push cd db))
WARNING: in ADD-RECORD : DB is neither declared nor bound,
it will be treated as if it were declared SPECIAL.
I can't understand what is going wrong. It cant be the code because I have tried in both clisp and sbcl, both get similar errors. Why is this occurring? Could my set-up be wrong?

You made a copy error from this text:
(defun add-record (cd) (push cd *db*))
where *db* (mind the * signs) refers to the previous
(defvar *db* nil)

Related

Why do executables have different behavior that the repl behavior?

My Setup
I develop common lisp with emacs + slime. My machine is a mac pro M1. And, I use the kitty terminal emulator.
The Situation
When I run my app (see code at the end) in the repl, it works fine.
When I create and run the executable, it's as if the order of the program is different.
For example, I have 5 questions which asks for user input...
(defpackage custom-sender
;; import the exactly the symbols I need from a package
(:import-from :cl-json :encode-json-to-string)
(:use :cl)
(:export :main))
(in-package custom-sender)
(defun main()
(asking-questions))
(defun asking-questions ()
(let ((firstname (prompt-read "What is the firstname of the contact?"))
(email (prompt-read "What is their email?"))
(job (prompt-read "What is the job?"))
(first-line (prompt-read "what is the first line of their address?"))
(sending-account (prompt-read "Which email account do you want to send from? (e2, e3 etc)")))
(status-update "some text ~a" email);; <-- this function is executed BEFORE the "sending-account" question is asked
... ) ;;<-- end of let block
)
(defun status-update (message value)
(format *query-io* (concatenate 'string message "~C~C") value #\linefeed #\linefeed)
(force-output *query-io*))
(defun prompt-read (question)
(format *query-io* "~a: " question)
(read-line *query-io*)
(force-output *query-io*))
The Problem
When running the executable, there are two issues:
The first function (status-update...) is executed before the final prompt read. In the terminal, the question comes up but immediately exits. So I cannot enter anything.
Also... (status-update...) gets the value of email which is NIL. Even though I entered a value inside the terminal.
This entire process runs perfectly in the repl.
Note - I am building the executable with the ASD MAKE process.
(defun prompt-read (question)
(format *query-io* "~a: " question)
(read-line *query-io*)
(force-output *query-io*))
change it to something like this:
(defun prompt-read (question)
(format *query-io* "~a: " question)
(force-output *query-io*)
(read-line *query-io*)
(force-output *query-io*))
Otherwise the prompt may not be visible when the function is waiting for input..., due to a buffering output stream.
Streams may or may not buffer output. For portable programs you'd need to add operations to clear or force output.

Emacs SLIME Common Lisp Undefined variable

I'm following Practical Common Lisp Chapter 3 codes.
I've save the following codes to an external files:
(defvar *db* nil)
(defun make-cd (title artist rating ripped)
(list :title title :artist artist :rating rating :ripped ripped))
(defun add-record (cd) (push cd *db*))
(defun dump-db ()
(dolist (cd *db*)
(format t "\~{\~a:\~10t\~a\~%\~}\~%" cd)))
I keep getting the following error when I tried to compile it inside Emacs:
compilation unit finished ;
Undefined variable: ;
*DB* ;
caught 1 WARNING condition
Could someone explain to me what is wrong with the code?
What is the different between compiling the above code vs running each line under SLIME?
thanks in advance.
the following is what i tried:
If i try compile all the above codes (cursor at very end), i get the undefined variable warning.
if i try and compile
(defvar *db* nil)
then rest of the code, I don't get the undefined variable warning (i tried this just before posting, but i was not getting this result in previous attempt, or maybe i did something extra in those previous attempts...).
i think i understand why I'm not getting an error with the 2nd method because the *db* is in memory already.
See the SLIME manual: Compilation Commands
C-c C-c only compiles individual toplevel forms. See the documentation how to compile a region or file.
As the people commented - that was also my suspicion that you didn't run the compiling command for the entire buffer.
To compile the entire file/buffer, do: C-c C-k.
Or mark all the code you want by
C-S- and for up p, down n, back b, forward f to be run
and then call M-x slime-compile-region.

sdl2:load-bmp Problem with current working directory, common-lisp

While trying to work through cl-sdl2-tutorial, I'm having trouble loading a bitmap due to a wrong current working directory.
I'd like to get a proper solution to the problem using relative path names.
A minimal working example:
Having modified the code of example two from above mentioned tutorial.
(defpackage #:sdl2-tutorial-2
(:use :common-lisp)
(:export :main))
(in-package :sdl2-tutorial-2)
(defparameter *screen-width* 640)
(defparameter *screen-height* 480)
(defmacro with-window-surface ((window surface) &body body)
`(sdl2:with-init (:video)
(sdl2:with-window (,window
:title "SDL2 Tutorial"
:w *screen-width*
:h *screen-height*
:flags '(:shown))
(let ((,surface (sdl2:get-window-surface ,window)))
,#body))))
(defun main(&key (delay 2000))
(format t " cwd: ~a, ~% dpd: ~a, ~& e-p: ~a, ~% pf: ~a, ~& load: ~a"
(sb-posix:getcwd)
*default-pathname-defaults*
(uiop:file-exists-p "hello_world.bmp")
(probe-file "hello_world.bmp")
(sdl2:load-bmp "hello_world.bmp"))
(with-window-surface (window screen-surface)
(let ((image (sdl2:load-bmp "hello_world.bmp")))
(break "1 here with ~a~%" image)
(setf image (sdl2:load-bmp "hello_world.bmp"))
(break "2 here with ~a~%" image)
(break "3 error: ~a~%" (sdl2-ffi.functions:sdl-get-error))
(sdl2:blit-surface image
nil
screen-surface
nil)
(sdl2:update-window window)
(sdl2:with-event-loop (:method :poll)
(:quit () t)
(:idle ()
(sdl2:delay delay))))))
Before compiling above code and running (main), I changed working directory in the REPL, via:
(sb-posix:chdir (truename "/test/cl-sdl2-tutorial/2/"))
(setf *default-pathname-defaults* (truename "/test/cl-sdl2-tutorial/2/"))
The above code prints, as expected, when running (main) in the REPL:
SDL2-TUTORIAL-2> (sdl2-tutorial-2:main)
0: (SDL2-TUTORIAL-2:MAIN)
cwd: /test/cl-sdl2-tutorial/2,
dpd: /test/cl-sdl2-tutorial/2/,
e-p: /test/cl-sdl2-tutorial/2/hello_world.bmp,
pf: /test/cl-sdl2-tutorial/2/hello_world.bmp,
load: #<SDL-SURFACE {#X7F5CBC018DD0}>
Problem:
The bitmap can not be found and therefore not loaded.
Calls to (sdl2:load-bmp "hello_world.bmp") always return a a zero pointer (#<SDL-SURFACE {#X00000000}>) and breakpoint 3 states:
3 error: Couldn't open /home/jue/hello_world.bmp
but evaling (sdl2:load-bmp "hello_world.bmp") during a break from breakpoints 1 or 2 or 3, is successful and continuing (main) displays the picture.
Questions:
Why is sdl2:load-bmp using the "wrong" working directory and why is it using the "correct" working directory during breakpoints?
How to make sdl2:load-bmp use the wanted working directory (instead of "/home/jue/") when using relative paths?
Remarks
(I'm using current released versions of sbcl, Emacs, sly on a Linux machine, if that matters. I'm only intermediate experienced with Common Lisp and its development environment, but advanced at elisp)
I suspect but don't know that the problem is that the sdl2 library is doing fanciness with threads, with the result that the working directory isn't what you think.
The solution to this in my experience is never to let the implementation second-guess you like that. In any case where there's some interface which says "do something to a file" give it an absolute pathname so it has no chance to do any thinking of its own. Do something like.
(defparameter *where-my-bitmaps-live* (merge-pathnames
(pathname "lib/bitmaps/")
(user-homedir-pathname)))
...
(defun load-a-bitmap (name)
(load-bmp (merge-pathnames (pathname name) *where-my-bitmaps-live*)))
And now it really has no excuse.
(You want to check that the above pathname-mergery is actually right: it seems to be for me but I forget the details of pathname rules every time I look away for more than a few minutes).

Modifying a list passed as a parameter gives different results in SBCL and CLISP

Can someone explain why I get different results for the following simple program with sbcl and clisp? Is what I am doing undefined by the language, or is one of the two lisp interpreters wrong?
; Modify the car of the passed-in list
(defun modify (a) (setf (car a) 123))
; Create a list and print car before and after calling modify
(defun testit () (let ((a '(0)))
(print (car a))
(modify a)
(print (car a))))
(testit)
SBCL (version 1.0.51) produces:
0
0
CLISP (version 2.49) produces (what I would expect):
0
123
I agree with Seth's and Vsevolod's comments in that this behavior is due to your modification of literal data. Try using (list 0) instead of '(0). Questions relating to this come up relatively frequently, so I'll quote the HyperSpec here.
3.7.1 Modification of Literal Objects:
The consequences are undefined if literal objects are destructively
modified.
The definition of "literal":
literal adj. (of an object) referenced directly in a program rather
than being computed by the program; that is, appearing as data in a
quote form, or, if the object is a self-evaluating object, appearing
as unquoted data. ``In the form (cons "one" '("two")), the expressions
"one", ("two"), and "two" are literal objects.''
Note that often (in many implementations), if you modify literal values, you'll really modify them in the code itself – writing self modifying code. Your example code will not work as you expect.
Your example code in CCL:
CL-USER> (defun modify (a) (setf (car a) 123))
MODIFY
CL-USER> (defun testit ()
(let ((a '(0)))
(print (car a))
(modify a)
(print (car a))))
TESTIT
CL-USER> (testit)
0
123
123
CL-USER> (testit)
123
123
123
Take a look at the second evaluation of testit, where the let itself really already contains the modified value, thus the first print also yields 123.
Also see: Lisp, cons and (number . number) difference, where I explained this in more detail, or the question linked in Vsevolod's comment above.

Statements not executing in order? (defvar within a let statement)

I've tried to reduce it to the minimal example. The code runs without an error, producing the expected output. But it gives me a warning that my first variable is undefined. It seems that the second statement of progn doesn't "see" the results of the first statement. Thanks for the help!
(I originally did not have the progn construct in the code at all, but after getting this error I added it to see if that would force execution in order -- but the error is the same.)
Here's the code:
(let ((input (open "input.lisp")))
(progn (defvar var1 (read input))
(defvar arr1 (make-array var1 :initial-contents (read input))))
(close input))
(print var1)
(print arr1)
These are the contents of the file "input.lisp":
9
(10 8 6 4 2 4 6 8 10)
And this is the output I get from sbcl after executing (load "test.lisp"):
; in: DEFVAR ARR1
; (MAKE-ARRAY VAR1 :INITIAL-CONTENTS (READ INPUT))
;
; caught WARNING:
; undefined variable: VAR1
;
; compilation unit finished
; Undefined variable:
; VAR1
; caught 1 WARNING condition
9
#(10 8 6 4 2 4 6 8 10)
T
So, it seems to me that both definition statements are executing, but the second doesn't "see" the results of the first. It still constructs the array correctly because it's filled with the given initial-contents. But why isn't var1 already defined?
See the documentation for defvar in the Hyperspec:
If a defvar or defparameter form appears as a top level form, the compiler must recognize that the name has been proclaimed special.
This implies (and it seems to be the case for SBCL) that if a defvar appears as a non-top-level form, then the compiler need not recognize that the name has been declared. So how come your defvars are not being compiled as top level forms? See section 3.2.3.1, Processing of Top Level Forms (point 6) for the answer: the let surrounding your code causes it to be compiled as non-top-level forms.
So you need to defvar your variables at top level, and then assign them later on with setf inside the let.
Like this. It's also usually simpler to use with-open-file rather than open and close.
(defvar var1)
(defvar arr1)
(with-open-file (input "input.lisp" :direction :input)
(setf var1 (read input))
(setf arr1 (make-array var1 :initial-contents (read input))))
(print var1)
(print arr1)
The reason that you are having this trouble is that you are placing your code at top level in the file. This is a slightly unusual thing to do: the normal Lisp coding style is to put most of your code in function definitions, and then to call those functions when you need to run them.
For example, this would be a more typical way to write this kind of code, with the initialization code in its own function.
(defvar *var1* nil "Documentation for var1.")
(defvar *arr1* nil "Documentation for arr1.")
(defun init-from-file (file)
"Read *var1* and *arr1* from file."
(with-open-file (input file :direction :input)
(setf *var1* (read input))
(setf *arr1* (make-array *var1* :initial-contents (read input)))))
(when (null *var1*) (init-from-file "input.lisp"))

Resources