I am trying to work through Practical Common Lisp. I'm a lisp beginner.
I've defined a package using "quicklisp" I load the package with (ql:quickload :spam filter)
One of the functions in this package looks like this:
(defun increment-count (feature type)
(ecase type
(ham (incf (ham-count feature)))
(spam (incf (spam-count feature)))))
When I try to call a function that calls this function in slime the case statement fails. I think it fails because the compiler has added the package name as a prefix to the clauses.
Here is the error I'm seeing:
HAM fell through ECASE expression. Wanted one of (HAM SPAM).
[Condition of type SB-KERNEL:CASE-FAILURE]
Restarts:
0: [RETRY] Retry SLIME REPL evaluation request.
1: [*ABORT] Return to SLIME's top level.
2: [ABORT] Abort thread (#)
Backtrace:
0: (SB-KERNEL:CASE-FAILURE ECASE HAM (SPAMFILTER::HAM SPAMFILTER::SPAM))
1: (SPAMFILTER:INCREMENT-COUNT # HAM)
2: (SPAMFILTER:TRAIN "From exmh-users-admin#redhat.com Mon Sep 23 12:06:27 2002 ..)
3: (SPAMFILTER::TRAIN-FROM-CORPUS #>((#P"/Users/jh/src/lisp/spamfilter/mail/easy_ham/1205.f9d66868c52039f7a147d9e2b4b05e1f" HAM) (#P"/Users/jh/src/lisp/spamfilter/mail/easy_ham/0090.314ec4268af7a3a1974d5e..
4: (SPAMFILTER:TEST-CLASSIFIER #((#P"/Users/jh/src/lisp/spamfilter/mail/easy_ham/0001.ea7e79d3153e7469e7a9c3e0af6a357e" HAM) (#P"/Users/jh/src/lisp/spamfilter/mail/easy_ham/0002.b3120c4bcbf3101e661161ee7..
5: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SPAMFILTER:TEST-CLASSIFIER SPAMFILTER:CORPUS 0.1) #)
6: (EVAL (SPAMFILTER:TEST-CLASSIFIER SPAMFILTER:CORPUS 0.1))
--more--
I'm basing my conjecture that the compiler has added the prefix on Backtrace 0:
0: (SB-KERNEL:CASE-FAILURE ECASE HAM (SPAMFILTER::HAM SPAMFILTER::SPAM))
I'm sure I'm missing something obvious.
Thanks.
This REPL transcript may be instructive. This doesn't have anything to do with the compiler adding anything, but that symbols in different packages aren't necessarily the same.
First, define a package and some a function using symbols in the spam-filter package:
CL-USER> (defpackage #:spam-filter
(:use "COMMON-LISP"))
#<PACKAGE "SPAM-FILTER">
CL-USER> (in-package #:spam-filter)
#<PACKAGE "SPAM-FILTER">
SPAM-FILTER> (defun test (x)
(ecase x
(ham "ham")
(spam "spam")))
TEST
Let's check that it works:
SPAM-FILTER> (test 'spam)
"spam"
OK, now let's go back to CL-USER:
SPAM-FILTER> (in-package "CL-USER")
#<PACKAGE "COMMON-LISP-USER">
Now let's try to call spam-filter::test:
CL-USER> (spam-filter::test 'spam)
; Evaluation aborted on #<SB-KERNEL:CASE-FAILURE expected-type:
(MEMBER SPAM-FILTER::HAM SPAM-FILTER::SPAM)
datum: SPAM>.
We get an error because the current package is CL-USER, so the reader reads the characters spam and interns "SPAM" to get the symbol cl-user::spam, which is not the same as spam-filter::spam. Let's try calling it with spam-filter::spam:
CL-USER> (spam-filter::test 'spam-filter::spam)
"spam"
And surely enough, it still works. For more about what's going on here, you might enjoy Ron Garret's The Complete Idiot’s Guide to Common Lisp Packages.
Ways to solve trying to compare symbols from different packages:
Usually it makes sense to make sure the symbols are in the right package. Normalize them into one package.
use keyword symbols
only compare the symbol names, but then you need to use something else than ECASE.
use strings, but then you need to use something else than ECASE.
Related
SBCL generates spurious style warnings about undefined functions. (The functions are defined, just later in the file.) I want to solve this problem once and for all. Fortunately, there is a way to do this:
(declaim (sb-ext:muffle-conditions style-warning))
The downside is that CCL, for obvious reasons, barfs on a program containing the above. I try to solve this problem with a conditional:
(#+sbcl (declaim (sb-ext:muffle-conditions style-warning)))
but now SBCL is unhappy: "illegal function call".
How do you put such a declaim into a portable program?
Note that while the existing answer is right, disabling warnings is not a good practice. In your case, it is probably not necessary.
Common Lisp has a notion of compilation unit, where multiple definitions are grouped together. This gives a chance for the compiler/interpreter to take care of cross-references among functions (an interpreter could collect warnings and keep only those that are not found later, for example).
For example, in file #P"/tmp/foo.pl":
(defun mut-rec-foo (x)
(when (plusp x)
(mut-rec-bar (1- x))))
(defun mut-rec-bar (x)
(print x)
(mut-rec-foo (1- x)))
Do not evaluate anything in the file; instead do:
(compile-file #P"/tmp/foo.pl")
; compiling (DEFUN MUT-REC-FOO ...)
; compiling (DEFUN MUT-REC-BAR ...)
; /tmp/foo.fasl written
; compilation finished in 0:00:00.002
No warning. You can then call (load #P"/tmp/foo.fasl") to have the definitions in your current lisp environment, without warnings.
Typically, ASDF and by extension Quicklisp use COMPILE-FILE, so your problem should disappear as soon as you bundle your files into a system.
You can also do:
(with-compilation-unit ()
(defun mut-rec-foo/bis (x)
(when (plusp x)
(mut-rec-bar/bis (1- x))))
(defun mut-rec-bar/bis (x)
(print x)
(mut-rec-foo/bis (1- x))))
Evaluating the whole block shows no warning for *EVALUATOR-MODE* being both :COMPILE or :INTERPRET.
What you witnessed happens when you evaluate each expression one after the other (or maybe one region after another one). There, the compiler has no way to know that the function already exists. Silencing the warning is the worse option, because you might actually have made an error.
If you know in advance that a function will exist, but not in your compilation unit (maybe it is only defined at runtime), the you can declaim that fact, as follows:
(declaim (ftype function my-function))
The above says that my-function must be assumed to be fbound to an object of type function. You could also give more information by refining what kind of function you claim it to be:
(declaim (ftype (function (number) (values string &optional)) num-to-string))
... for a function that accepts a number and returns exactly one value, a string.
(declaim (ftype (function () nil) forever-loop))
... for a function that accepts nothing and never return a value (loop or signals an error).
Omit the outer pair of parentheses:
#+sbcl (declaim (sb-ext:muffle-conditions style-warning))
As you are using declaim, I assume, that the declaration appears at the top-level of a compilation unit. If you need to group multiple top-level statements, you can wrap them all with a progn (which doesn't change the "top-level"-ness).
The reason SBCL did complain is, that its reader reads
((declaim (sb-ext:muffle-conditions style-warning)))
(as the :SBCL feature is present), which is simply a syntax error. CCL does not complain, because its reader reads
()
which is simply another way to spell nil.
I try to use Common Lisp packages, but I have several (probably naming conventions) problems, first is the use of "#:" it seems not necessary but is like sharp-quote in functions that is better to use depending on your context.
(defpackage #:match-test
(:use #:match
#:fiveam
#:cl)
(:export #:run!
#:test-match)
(:documentation "Test package for testing match project 1 of CS202"))
Then is in how to use that package
(in-package #:match-test)
(in-package :match-test)
(in-package match-test)
it works, but when I want to delete that package it only works with:
CL-USER> (delete-package (in-package #:match-test))
#<BOOLEAN <<error printing object>> {2010004F}>
it gives that error, but it makes the job done. It seems working with the package as an object, I also do not understand the hyperspec, is a problem that I need to learn CLOS, that is true I'm a beginner learning Lisp, but I suppose that I can get a easy clarifying for my doubts.
I hope that I said it quite clearly.
Finally I want to say that I used emacs + sly + roswell and
CL-USER> (lisp-implementation-type)
"SBCL"
CL-USER> (lisp-implementation-version)
"1.4.6"
DEFPACKAGE and IN-PACKAGE are defined as macros. They take a literal name - a string designator: foobar, |FOOBAR|, #:FOOBAR, :FOOBAR or "FOOBAR".
DELETE-PACKAGE is a function and expects a string designator, too. But since it is a function, the argument is evaluated. This means: if you want to pass the name, you have to quote it - if it is a symbol not in the keyword package. Strings and keyword symbols are self-evaluating and don't need to be quoted. Valid arguments to DELETE-PACKAGE are for example:
'foobar
'|FOOBAR|
'#:FOOBAR
:FOOBAR or ':FOOBAR
"FOOBAR" or '"FOOBAR"
Since DELETE-PACKAGE is a function, the argument gets evaluated -> you can also evaluate variables, function calls, ... as argument.
The Error: Deleting the current package
LispWorks:
CL-USER 43 > (delete-package (in-package #:match-test))
Error: Cannot delete the current package, #<The MATCH-TEST package, 0/16 internal, 2/16 external>.
1 (abort) Return to top loop level 0.
SBCL:
* (delete-package (in-package #:match-test))
debugger invoked on a SIMPLE-TYPE-ERROR in thread
#<THREAD "main thread" RUNNING {10005605B3}>:
*PACKAGE* can't be a deleted package:
It has been reset to #<PACKAGE "COMMON-LISP-USER">.
Your code tries to delete the current package - you just used IN-PACKAGE to make it the current package - deleting the current package is usually not a good idea. You are shooting yourself in the foot. A Lisp might prevent that (like my example in LispWorks) or allow it - but then you have to live with the consequence.
I use packages a lot and the exported symbols often change their names. When I try to recompile the package I get warnings like this:
package.lisp:3:1:
warning:
MY-PROJECT also exports the following symbols:
(OLD-SYMBOL1 OLD-SYMBOL2 OLD-SYMBOL3)
See also:
Common Lisp Hyperspec, DEFPACKAGE [:macro]
SBCL Manual, *ON-PACKAGE-VARIANCE* [:variable]
--> EVAL-WHEN
==>
(SB-IMPL::%DEFPACKAGE "MY-PACKAGE" '("KE") 'NIL 'NIL 'NIL '("CL") 'NIL
'NIL '("NEW-EXPORTED-SYMBOL1" "NEW-EXPORTED-SYMBOL2") '("MY-PROJECT") 'NIL
...)
I know that I can use (unintern 'old-symbol1) to signal the system I don't want to use that symbol anymore. However this is becoming very tedious when there is a lot of renaming.
My questions are:
1) Is is possible to signal to sbcl or emacs to unintern the old/previously exported symbols automatically?
2) If not - is it possible to get all "old" symbols in a variable?
My plan for 2) is to make a key binding to something like (apply #'unintern *old-symbols*)
Setting the variable *on-package-variance* to a list (:error t) will give you an error instead of a warning when redefining the package. The error will have a restart DROP-THEM to unexport the symbols.
You can add
(setf *on-package-variance* '(:error t))
to your ~/.sbclrc to have it always set when starting up SBCL.
First I don't think you want to unitern symbols. Unintern removes them from the package. I think you want to unexport them to avoid the warning. You can do that with the following function
(defun unexport-package-symbols (package)
(do-symbols (symbol package)
(destructuring-bind (symbol status)
(find-symbol (symbol-name symbol) package)
(when (eq status :external)
(cl:unexport symbol package)))))
;; It takes a package-designator as an argument.
(unexport-package-symbols "MY-PACKAGE")
All I wanted was to load an initialisation file for swank which wouldn't affect my lisp when it's started without swank...
I first tried #+swank (defun...) in my file that's loaded from ccl-init (trying this on ccl 1.10 + windows), and soon realised it's sourced before swank is loaded (obviously).
My aim is to define a simple function in :cl-user everytime I start swank. I just ended up with a swank add-hook to load my init.lisp file, and since I want to define the function in cl-user, I tried this in the init.lisp:
(let ((current-package *package*))
(in-package :cl-user)
(defun cd (dir)
(swank:set-default-directory
(parse-namestring dir)))
(in-package current-package))
Now, I don't recall if a defun in let was allowed, but lisp doesn't complain for it, but rather tells me that cur-pck symbol doesn't exist, and it seems when we switch the package, cur-pck binding gets out of scope. I thought cur-pck is a lexical binding, and that it should be reachable from within the lexical region, being independent from a package, am I wrong?
Why do I switch packages? I'm thinking that loading this file from swank at some initialisation point will define things in some swank package, that's why I wanted to try switching to cl-user first, define the function symbol, and switch back to let swank do it's thing.
At this point I guess I need someone to tell me I'm approaching the problem from the wrong angle, and that I should better choose an easier solution.
Additionally, out of curiosity in case above is the complete wrong approach, is there a way to define a symbol in another package within a function or a closure?
Switching packages in a form has no direct effect on the form
Let's look at this:
(in-package "FOO")
(let ((x 10))
(in-package "BAR")
(setf x 20))
Which x does it set to 20? FOO::X or BAR::X?
Well, it is FOO::X. Switching packages during execution has no effect on the symbols already read. The whole let form is read at once and the *package* value is used for that. Having an IN-PACKAGE in the form itself has no effect on the form itself.
Symbol with a package prefix
If you want to use a symbol in a certain package, just write the package prefix:
cl-user:foo ; if FOO is exported and the package exists
or
cl-user::foo ; if foo is not exported and the package exists
for example:
(defun cl-user::cd (...) ...)
Computing with symbols
You can also compute new symbols in packages you don't know yet:
(let ((sym-name "A-NEW-SYMBOL")
(my-package-name "SOME-EXISTING-PACKAGE"))
(intern sym-name my-package-name))
If the package does not exist, you can create it.
You can also set the function of a computed symbol:
(setf (symbol-function (compute-a-function-symbol))
#'(lambda ()
'foo))
If you want to define a function in a different package that the current one you can use a qualified symbol for a name
(defun cl-user::cd (dir)
(swank:set-default-directory
(parse-namestring dir)))
The binding is not being "lost". To test so yourself add (princ cur-pck) before the in-package form.
If you try evaluating (in-package *package*) you will see why your code fails to switch packages. The in-package macro does not evaluate its argument. The code that would give us the code we would want to evaluate is:
(let ((cur-pck *package*))
(in-package :cl-user)
(defun cd (dir)
(swank:set-default-directory
(1+ 2)))
(princ cur-pck)
`(in-package ,cur-pck))
However, as Rainer Joswig noted in his answer the in-package has no effect on forms already read, so it wouldn't work as desired even as a macro.
A style nitpick, don't use abbreviations, write current-package.
IN-PACKAGE is a macro, not a function. The problem in your code is that saying (in-package cur-pck) tries not to switch into the package denoted by the cur-pck variable but to the package named CUR-PCK (which obviously does not exist).
You can set the package temporarily with
(let ((*package* (find-package :cl-user)))
(defun cd (dir)
...))
But then again, the easiest way to achieve what you are doing would be
(defun cl-user::cd (dir)
...)
which totally eliminates the need to set the current package.
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.