Sample code in Touretzky's book causes Error at Let* - common-lisp

Sample code in page 144 of Touretzky's Lisp book causes error on my environment. Is anything wrong with how I run?
(defun price-change (old new)
(let* ((diff (- new old))
(proportion (/ diff old))
(percentage (* proportion 100.0)))
(list ’widgets ’changed ’by percentage
’percent))
)
Here's the error. I don't understand why string "widgets" is evaluated...
Break 5 [7]> (price-change 1.25 1.35)
*** - LET*: variable ’WIDGETS has no value
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead of ’WIDGETS.
STORE-VALUE :R2 Input a new value for ’WIDGETS.
ABORT :R3 Abort debug loop
ABORT :R4 Abort debug loop
ABORT :R5 Abort debug loop
ABORT :R6 Abort debug loop
ABORT :R7 Abort debug loop
ABORT :R8 Abort main loop
Environment: Ubuntu 11.10, GNU CLISP 2.49

You need to use the quote character apostrophe: '. You did not. You have used a right quotation mark.

Related

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.

SBCL Built executable: "When attempting to set the slot's value to XXX (SETF of SLOT-VALUE), the slot YYY is missing from the object"?

It's completely fine to run #'cl-state-machine-examples/tamagochi:run,
But generated executable signals SIMPLE-ERROR like this:
Built: https://github.com/ageldama/cl-state-machine/releases/tag/fail-sbcl-slot-value
And I get:
$ ./tamagochi.exe
debugger invoked on a SIMPLE-ERROR in thread
#<THREAD "main thread" RUNNING {10005384C3}>:
When attempting to set the slot's value to 5 (SETF of SLOT-VALUE), the slot
MONEY is missing from the object
#<CL-STATE-MACHINE-EXAMPLES/TAMAGOCHI::TAMAGOCHI-STATUS {1001B7B9B3}>.
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 from the current thread.
((:METHOD SLOT-MISSING (T T T T)) #<unused argument> #<CL-STATE-MACHINE-EXAMPLES/TAMAGOCHI::TAMAGOCHI-STATUS {1001B7B9B3}> MONEY SETF 5) [fast-method]
0]
using:
Uname -a : Linux arch-desktop 5.3.11-arch1-1 #1 SMP PREEMPT Tue, 12
Nov 2019 22:19:48 +0000 x86_64 GNU/Linux
https://github.com/ageldama/cl-state-machine/releases/tag/fail-sbcl-slot-value
Both for:
- sbcl-1.5.0-x86-64-linux AND sbcl-1.5.9-x86-64-linux/
Build log is:
This is SBCL 1.5.9, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
WARNING: redefining UIOP/PACKAGE:FIND-PACKAGE* in DEFUN
...CUT...
WARNING: redefining UIOP/BACKWARD-DRIVER:VERSION-COMPATIBLE-P in DEFUN
[undoing binding stack and other enclosing state... done]
[performing final GC... done]
[defragmenting immobile space... (fin,inst,fdefn,code,sym)=1062+946+18321+18719+25423... done]
[saving current Lisp image into /home/jhyun/P/cl-state-machine/tamagochi.exe:
writing 0 bytes from the read-only space at 0x50000000
writing 432 bytes from the static space at 0x50100000
writing 27852800 bytes from the dynamic space at 0x1000000000
writing 2011136 bytes from the immobile space at 0x50300000
writing 12144640 bytes from the immobile space at 0x52100000
done]
Thank you in advance!
My guess would be that your keyword->symbol function interns into the wrong package, because the read in there is executed from a different one:
(defun keyword->symbol (kw-or-symbol)
(with-input-from-string (s-in (string kw-or-symbol))
(read s-in)))
I'd use intern to create the symbol:
(defun keyword->symbol (kw-or-symbol)
(intern (symbol-name kw-or-symbol)
#.*package*))
The #.*package* construct gives the value of *package* at read time, i. e. when the function form above was read.

Quickload inside eval-when

Here's a strange situation. I have this code:
(eval-when (:compile-toplevel :load-toplevel :execute)
(ql:quickload "cffi-grovel")
(setf cffi-grovel::*cc* "mpicc")) ; <--- this is the line it complains about.
Which I belive has to load cffi-grovel package before setting cffi-grovel::*cc* variable. When this form is executed from SLIME it works, but it doesn't work when loaded directly by SBCL, here's the output:
$ sbcl --noinfo
* (ql:quickload "cl-mpi")
debugger invoked on a LOAD-SYSTEM-DEFINITION-ERROR in thread
#<THREAD "main thread" RUNNING {10029C0E43}>:
Error while trying to load definition for system cl-mpi from pathname
/home/wvxvw/quicklisp/local-projects/cl-mpi/cl-mpi.asd:
READ error during COMPILE-FILE:
Package CFFI-GROVEL does not exist.
Line: 6, Column: 25, File-Position: 264
< restarts ... >
* (ql:quickload "cffi-grovel")
To load "cffi-grovel":
Load 1 ASDF system:
cffi-grovel
; Loading "cffi-grovel"
..
("cffi-grovel")
* (ql:quickload "cl-mpi")
To load "cffi-grovel":
Load 1 ASDF system:
cffi-grovel
; Loading "cffi-grovel"
To load "cl-mpi":
Load 1 ASDF system:
cl-mpi
; Loading "cl-mpi"
; mpicc -m64 ...
; ...
.
("cl-mpi")
Why does it fail the first time?
PS. I also tried #.cffi-grovel::*cc* instead - same result.
It fails because Lisp reads every form before executing it. And when it reads it, package cffi-grovel indeed does not exist yet, because cffi-grovel is loaded at execution time (whatever it means for form wrapped with eval-when).
Try spliting the eval-when form into two eval-whens: ql:quickload and setf. Or write something like this:
(setf (symbol-value (find-symbol "*CC*" "CFFI-GROVEL"))
"mpicc")
monoid gives a good answer. Here is a slightly shorter form.
Find the symbol at runtime, when the package actually exists. Note the use of SET, not SETF here:
(set (find-symbol "*CC*" "CFFI-GROVEL") "mpicc")
To make it more robust, one would need to check that FIND-SYMBOL actually finds the symbol.
The following function also gives you meaningful error messages and restarts:
(defun set-runtime-symbol (name package value)
(assert (find-package package) (package))
(assert (find-symbol name package) (name))
(set (find-symbol name package) value))
Alternatively use two EVAL-WHEN statements, instead of one.
OK, finally figured it I can do it like so:
(setf #.(intern "cffi-grovel::*cc*") "mpicc")
But I'm not sure how much this is fail-safe.

Increasing Stack Space

When I run the following code:
(defun countdown (n)
(if (>= n 0)
(cons n (countdown (- n 1)))))
(countdown 100000)
I get the following message :
INFO: Control stack guard page unprotected
Control stack guard page temporarily disabled: proceed with caution
debugger invoked on a SB-KERNEL::CONTROL-STACK-EXHAUSTED in thread
#<THREAD "main thread" RUNNING {1002B03653}>:
Control stack exhausted (no more space for function call frames).
This is probably due to heavily nested or infinitely recursive function
calls, or a tail call that SBCL cannot or has not optimized away.
PROCEED WITH CAUTION.
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-KERNEL::CONTROL-STACK-EXHAUSTED-ERROR)
How do I increase the stack space? I do not want to change the code above; I supplied it purely to illustrate stack exhaustion.
Calling sbcl with the --help option on the command line gives some useful common options, including an option for how to increase the stack space. You want to to use the --control-stack-size argument.
$ sbcl --help
Usage: sbcl [runtime-options] [toplevel-options] [user-options]
Common runtime options:
--help Print this message and exit.
--version Print version information and exit.
--core <filename> Use the specified core file instead of the default.
--dynamic-space-size <MiB> Size of reserved dynamic space in megabytes.
--control-stack-size <MiB> Size of reserved control stack in megabytes.
...
By specifying a bigger value there, we can run your code:
$ sbcl --control-stack-size 100000
* (defun countdown (n)
(if (>= n 0)
(cons n (countdown (- n 1)))))
;=> (100000 … 6 5 4 3 2 1 0)
Not exactly in time for the question at hand, but for anyone also wondering about the --control-stack-size:
From the SBCL manual section "3.3.1 Runtime Options" the default value for the --control-stack-size is 2 megabytes.
So for a list containing 100k 64bit-integers 7 megabyte sbcl --control-stack-size 7 should be sufficient!
As a reference:
CL-USER> (type-of 42)
(INTEGER 0 4611686018427387903)
CL-USER> (/ (* 64 100e3) (expt 2 20))
6.1035156

ESS: ess-request-a-process defaults to "S"

Quite often I find myself with bunch of R processes running in ESS buffers. There's a convenient Lisp function ess-request-a-process that asks for R process, and brings it to front. The only downside is that it somehow defaults to S, so each time I'm about to make a switch, I have to type R, ad nauseam.
I tried customising the ess-language variable, but even if I set value to "R", i.e. 4 for current session, or even if I save settings for future session, as soon as I type C-c C-k, automagically S appears once again. It's very annoying, and I really don't want to end up with C-x C-b and then C-s for desired R session! =)
I even tried setting (setq-default ess-language "R") in .emacs, but with no luck...
BTW, I'm running Emacs v. 23.1.1 on Linux Mint and Emacs v. 23.2 on Arch Linux, with ESS v. 5.12. If that's relevant, I run Emacs from terminal with -nw argument. Here's my .emacs:
;; start server
(server-start)
;; load ESS
(require 'ess-site)
(require 'ess-rutils)
;; set HTML help as default
(setq inferior-ess-r-help-command "help(\"%s\", help_type = \"html\")\n")
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(ess-help-kill-bogus-buffers t)
'(ess-rutils-keys nil)
'(show-paren-mode t))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)
(put 'upcase-region 'disabled nil)
So... how to set R once and for all? (I don't use S/S+/SAS)
I did not know about this function so far. C-c C-k is bound to ess-force-buffer-current in ESS buffers.
[edit: C-c C-k is indeed bound to ess-request-a-process in iESS, in ESS it's ess-force-buffer-current]
In any case the variable you have to customize is ess-dialect
(setq-default ess-dialect "R")
It's buffer-local variable and some other stuff in ess-mode-hook might set it a different value.
Check it in each buffer with C-h v ess-dialect
Additionally, if you already running several processes then ess-switch-process (C-c C-s) might be the right way to go.
[edit: it will not jump to a process but just reset the associated process of the current ESS buffer]
[edit: After dwelling deeper on the issue it turned out that ess-request-a-process uses ess-language variable were the ess-dialect seems to be more appropriate. The problem is that each time an ess-inferior process starts it resets the global value of ess-language. This is why setting it in your case didn't work.
Here is a quick fix:
(defun ess-set-language ()
(setq-default ess-language "R")
(setq ess-language "R")
)
(add-hook 'ess-post-run-hook 'ess-set-language t)
]

Resources