I have a very weird requirement that lexically binding a special variable of another package.
In file A.lisp
(defpackage A
(:use #:CL)
(:export #:a-test))
(in-package A)
(declaim (special *a-sp-v*))
(defun a-test (&key (v *a-sp-v*))
(print v))
in file B.lisp
(defpackage B
(:use #:CL #:A))
(in-package B)
(defun b-test ()
(let ((*a-sp-v* 1)) ; cannot let a-test know
(a-test)))
I keep receiving the error The variable A::*A-SP-V* is unbound. in my REPL.
Are there some methods I can bind *a-sp-v* in the package B? Let a-test function running with special *a-sp-v* no matter what package it is in?
Your code is fine (I would use defvar instead of declaim special though).
You can bind any symbol, it does not matter which package it resides in.
You just need to make sure you bind the symbol you need to bind and not something else.
E.g., since you are not exporting a::*a-sp-v* from a, your b-test binds b::*a-sp-v* rather than a::*a-sp-v*.
If you replace *a-sp-v* with a::*a-sp-v* in b-test, it should work.
Alternatively, you can add #:*a-sp-v* to the :export section in (defpackage A ...)
Related
In most of the examples on the Internet, symbol equality is straight-forward:
(eq 'sym 'sym)
t
In my program, I want to compare symbols in a custom package:
(defpackage #:my-package
(:use #:common-lisp)
(:export #:my-function))
(in-package #:my-package)
(defun my-function (value)
(cond
((eq value 'sym)
(format t "SYM: YES~%"))
(t
(format t "SYM: NO~%"))))
(in-package #:common-lisp)
(my-package:my-function 'sym)
But when this code is executed, it displays:
SYM: NO
It seems like the 2 symbols are different:
(eq 'sym 'my-package::sym)
nil
The reason seems easy to understand, a symbol interned in a given package is not equal to a symbol with the same name interned in another package. Fair enough! But what is the idiom to compare 2 symbols, regardless the package?
Should we convert it to a string in a first place and compare strings?
(defpackage #:my-package
(:use #:common-lisp)
(:export #:my-function))
(in-package #:my-package)
(defun my-function (value)
(cond
((string= (symbol-name value) "SYM")
(format t "SYM: YES~%"))
(t
(format t "SYM: NO~%"))))
(in-package #:common-lisp)
(my-package:my-function 'sym)
The result is better, but there is an obvious issue regarding the character case.
How to check that 2 symbols are the same regardless their package?
The usual idiom is string=, which compares the names of symbols without regard to identity.
For example:
(eq 'x:a 'y:a) => nil
(string= 'x:a 'y:a) => t
I think you are confused about what 'being the same symbol' means.
Two symbols are the same symbol iff they are eq, which means that if they are not eq they are not the same symbol. In particular if two symbols have home packages which are different (again: not eq) they are not the same symbol.
If you want to know if two symbols have the same name then simply compare their symbol-names, as strings. But two symbols which merely have the same name are not necessarily the same symbol (for instance (eq '#:foo '#:foo) is false).
There are cases where it is useful to know whether two symbols have the same name (for instance the loop macro must do this so that (loop for ...) and (loop :for ...) mean the same thing) but these cases are fairly rare.
If what you want to do is know if two symbols have the same names you quite likely should be using strings instead.
If what you actually want to know is whether two symbols accessed from different packages are really the same symbol (so (eq 'x:foo 'y:foo), say) then eq is the appropriate test, and understanding the package system also helps.
The function find-data-from-command works fine when I run it without first doing the 'quickload' of the package. If I load the package it gives the error that split-sequence is undefined.
I have tried to reload split-sequence after loading the custom package. Doesn't work
(ql:quickload :<a-custom-package>)
(defun find-data-from-command (x desired-command)
(setq desired-data ())
(loop for line = (read-line x nil)
while (and line (not desired-data)) do
(progn
(setq commands (first (split-sequence ":" line)))
(setq data (split-sequence "," (first (rest (split-sequence ":" line)))))
(print (cons "command:" commands))
(cond
((equal commands desired-command) (return-from find-data-from-command data))))))
FIND-DATA-FROM-COMMAND
SIGMA 24 >
(setq obj-type (find-data-from-command (open "log.txt") "types"))
Error: Undefined operator SPLIT-SEQUENCE in form (SPLIT-SEQUENCE ":" LINE).
The problem is nothing to do with Quicklisp, it's to do with a package you've defined somewhere called SIGMA. In particular somewhere in your code is a form which looks like:
(defpackage "SIGMA" ;or :sigma or :SIGMA or #:sigma or ...
...
(:use ...)
...)
And then later
(in-package "SIGMA")
And the problem with this is that your package definition has an explicit (:use ...) clause.
defpackage, and the underlying function make-package has slightly interesting behaviour for the :use clause (or keyword argument in the case of make-package):
if none is given then there is an implementation-defined default;
if one is given then it overrides the default.
The idea, I think, is that implementations may want to provide a bunch of additional functionality which is available by default, and this functionality can't be in the CL package since the contents of that package is defined in the standard. So if you just say
(defpackage "FOO")
Then the implementation is allowed (and, perhaps, encouraged), to make the use-list of FOO have some useful packages in it. These packages might be the same ones that are in the default use-list of CL-USER, but I'm not sure that's required: the whole thing is somewhat under-specified.
The end result of this is that if you want to define packages which both make use of implementation-defined functionality and have explicit use-lists you have to resort to some slight trickery. How you do this is slightly up to you, but since you are by definition writing implementation-dependent code where you are defining packages like this, you probably want to make it clear that what you are doing is implementation-dependent, by some form like
(defpackage :foo
(:use ...)
#+LispWorks
(:use :lispworks :harlequin-common-lisp :cl)
...)
Or, if you just want some particular set of symbols
(defpackage :foo
(:use ...)
#+LispWorks
(:import-from :lispworks #:split-sequence))
Note that this is not quite the same thing as using a package containing the symbol.
In all these cases if your code has pretensions to be portable then there should be appropriate clauses for other implementations and a way of knowing when you're trying to run on an implemention you haven't yet seen: how to do this is outwith the scope of this answer I think.
Solved it.
The quickloading of the custom package was taking me into the package. I did not realize that. So I had to specify split-sequence is from outside. So, I replaced all occurrences of split-sequence in the function definition with
LISPWORKS:split-sequence
Then it worked.
If any one has a better solution, please do let me know. Thanks
i am having problem exporting a macro, it works when in it is declared in the same package, but not when it is imported. I use Emacs, SLIME, Clozure on Windows.
Package file
(defpackage :tokenizer
(:use :common-lisp)
(:export :tokenize-with-symbols
:current-token
:advanze-token
:peek-token
:with-token-and-peek
:with-token))
(defpackage :csharp-parser
(:use :common-lisp :tokenizer)
(:import-from :tokenizer :with-token-and-peek :with-token))
Tokenizer file
(in-package :tokenizer)
(defmacro with-token-and-peek (&body body)
`(let ((token (current-token tokenizer))
(peek (peek-token tokenizer)))
,#body))
Parser file
(in-package :csharp-parser)
(defun expression (tokenizer node-stack)
(with-token-and-peek
(cond ((is-number? token) (make-value-node "number" token))
((is-bool? token) (make-value-node "bool" token))
((is-identifier? token peek) (make-identifier-node tokenizer node-stack))
(t (make-ast-node :identifier "bla")))))
Gives the errors on compile:
csharpParser.lisp:265:3:
warning: Undeclared free variable TOKENIZER::TOKENIZER (2 references)
style-warning: Unused lexical variable TOKENIZER::PEEK
style-warning: Unused lexical variable TOKENIZER::TOKEN
csharpParser.lisp:266:14:
warning: Undeclared free variable TOKEN
etc etc etc
If i try a macroexpansion in package :csharp-parser
(macroexpand-1 '(with-token-and-peek tok))
(LET ((TOKENIZER::TOKEN (CURRENT-TOKEN TOKENIZER::TOKENIZER))
(TOKENIZER::PEEK (PEEK-TOKEN TOKENIZER::TOKENIZER)))
TOK)
T
Now like i said if i move the macros to the parser file, it compiles and works perfectly. But when i try to refactor it to the tokenizer file and export it via the package system it gives these errors, because it seems to internalize the symbol to the calling package. I have tried multiple ways via the colons, but can't get it to work.
If anybody could help me with this i would be very thankful.
The symbols TOKEN and PEEK in the macro are interned in the TOKENIZER package, while the code inside the COND uses symbols interned in the CSHARP-PARSER package. There are two ways around this.
Have the expansion use a symbol interned in the package where the code is. This can be done by manually interning a symbol in the current package while expanding the macro. For example:
(defpackage #:foo
(:use #:cl)
(:export #:aif))
(in-package #:foo)
(defmacro aif (test then &optional else)
(let ((it (intern (symbol-name 'it))))
`(let ((,it ,test))
(if ,it ,then ,else))))
(in-package :cl-user)
(use-package :foo)
(aif (+ 3 3) it) ;=> 6
Using (intern (symbol-name 'it)) instead of just (intern "IT") is a way of avoiding problems in case the lisp doesn't convert symbols to uppercase.
Have the code use the symbol interned in the tokenizer package. This can be done by exporting the symbol.
(defpackage #:foo
(:use #:cl)
(:export #:aif
#:it))
(in-package #:foo)
(defmacro aif (test then &optional else)
`(let ((it ,test))
(if it ,then ,else)))
(in-package :cl-user)
(use-package :foo)
(aif (+ 3 3) it) ;=> 6
The drawback is that the user of the macro must import the symbol, so they can't use the package qualified name for the macro.
(defpackage #:foo
(:use #:cl)
(:export #:aif
#:it))
(in-package #:foo)
(defmacro aif (test then &optional else)
`(let ((it ,test))
(if it ,then ,else)))
(in-package :cl-user)
(foo:aif (+ 3 3) it) ; Fails
This happened because the macro with-interned-symbols expanded to code which includes symbols interned in TOKENIZER, while the cond expression has only symbols interned in CSHARP-PARSER. Any symbols (other than keywords or gensyms) that a macro expansion includes should be interned.
The following macro will intern a list of symbols to variables of the same name:
(defmacro with-interned-symbols (symbol-list &body body)
"Interns a set of symbols in the current package to variables of the same (symbol-name)."
(let ((symbol-list (mapcar (lambda (s)
(list s `(intern (symbol-name ',s))))
symbol-list)))
`(let ,symbol-list ,#body)))
The macro with-token-and-peek can be redefined this way using the above to avoid this mismatch:
(with-interned-symbols (token peek)
(defmacro with-token-and-peek (&body body)
`(let ((,token (current-token tokenizer))
(,peek (peek-token tokenizer)))
,#body)))
Note that while anaphoric macros might be the most obvious special case here, this can happen in any macro that introduces new symbols to the expansion, with the exception of keywords as they are always in the keyword package.
Is there a way to temporarily import a few functions from a package into the current package, using standard common-lisp functions/macros?
I couldn't find one and had to roll my own. I'd rather not have to code anything up, or introduce another language construct, if the standard already provides such functionality.
(defmacro with-functions (functions the-package &body body)
"Allows functions in the-package to be visible only for body.
Does this by creating local lexical function bindings that redirect calls
to functions defined in the-package"
`(labels
,(mapcar (lambda (x) `(,x (&rest args)
(apply (find-symbol ,(format nil "~:#(~a~)" x)
,the-package)
args)))
functions)
,#body))
Example usage:
(defclass-default test-class ()
((a 5 "doc" )
(b 4 "doc")))
#<STANDARD-CLASS TEST-CLASS>
CL-USER>
(with-functions (class-direct-slots slot-definition-name) 'sb-mop
(with-functions (slot-definition-initform) 'sb-mop
(slot-definition-initform
(car (class-direct-slots (find-class 'test-class))))))
5
CL-USER>
EDIT: Incorporated some of Rainer's suggestions to the macro.
I decided to keep the run-time lookup capability, at the time cost of the run-time lookup to find the function in the package.
I tried to write a with-import macro that used shadowing-import and unintern, but I couldn't get it to work. I had issues with the reader saying that the imported functions didn't exist yet (at read time) before the code that imported the functions was evaluated.
I think getting it to work with shadowing-import and unintern is a better way to go, as this would be much cleaner, faster (no run-time lookup capability though) and work with functions and symbols in packages.
I would be very interested to see if someone can code up a with-import macro using unintern and shadowing-import.
It makes runtime function calls much more costly: it conses an arg list, looks up a symbol in a package, calls a function through the symbol's function cell.
It only works through symbols, not lexical functions. That makes it less useful in cases, where code is generated via macros.
Its naming is confusing. 'import' is a package operation and packages deal only with symbols, not functions. You can't import a function in a package, only a symbol.
(labels ((foo () 'bar))
(foo))
The lexical function name FOO is only in the source code a symbol. There is no way to access the function through its source symbol later (for example by using (symbol-function 'foo)). If a compiler will compile above code, it does not need to keep the symbol - it is not needed other than for debugging purposes. Your call to APPLY will fail to find any function created by LABELS or FLET.
Your macro does not import a symbol, it creates a local lexical function binding.
For slightly similar macros see CL:WITH-SLOTS and CL:WITH-ACCESSORS. Those don't support runtime lookup, but allow efficient compilation.
Your macro does not nest like this (here using "CLOS" as a package, just like your "SB-MOP"):
(defpackage "P1" (:use "CL"))
(defpackage "P2" (:use "CL"))
(with-import (p1::class-direct-slots) 'CLOS
(with-import (p2::class-direct-slots) 'P1
(p2::class-direct-slots (find-class 'test-class))))
The generated code is:
(LABELS ((P1::CLASS-DIRECT-SLOTS (&REST ARGS)
(APPLY (FIND-SYMBOL "CLASS-DIRECT-SLOTS" 'CLOS) ARGS)))
(LABELS ((P2::CLASS-DIRECT-SLOTS (&REST ARGS)
(APPLY (FIND-SYMBOL "CLASS-DIRECT-SLOTS" 'P1) ARGS)))
(P2::CLASS-DIRECT-SLOTS (FIND-CLASS 'TEST-CLASS))))
You can use import with a list of qualified symbols (i.e. package:symbol or package::symbol) you want to import and then unintern them.
I realized that a certain section of my code consists of groups of methods that look similar (like I have multiple trios: a helper function that gets called by two other functions meant for the programmer). I'm trying to write a macro that will define these three functions for me so that all I need to do is call the macro. But my attempt results in defuns and function calls that have quoted strings instead of the generated names as new symbols. What am I doing wrong?
Example (incorrect code)
(defmacro def-trio (base-name)
(let
((helper-name (format nil "helper-~a" base-name))
(method-1 (format nil "~a-1" base-name))
(method-2 (format nil "~a-2" base-name)))
`(progn
(defun ,helper-name () 'helper-called)
(defun ,method-1 () (,helper-name) '1-called)
(defun ,method-2 () (,helper-name) '2-called))))
Now the following happens:
(def-trio my-trio)
==>
(PROGN (DEFUN "helper-MY-TRIO" () 'HELPER-CALLED)
(DEFUN "MY-TRIO-1" () ("helper-MY-TRIO") '1-CALLED)
(DEFUN "MY-TRIO-2" () ("helper-MY-TRIO") '2-CALLED))
Also, after I learn how to get this working, are there any extra gotcha's if I had this macro define other macros instead of other functions? I read How do I write a macro-defining macro in common lisp but I think my question is a little different because I'm asking about programmatically generated symbols/names. I'm open to being corrected though :) Thanks!
Try this:
(defmacro def-trio (base-name) ; changes:
(let* ; 3.
((package (symbol-package base-name)) ; 2.
(helper-name (intern (format nil "HELPER-~a" base-name) package)) ; 1. 4.
(method-1 (intern (format nil "~a-1" base-name) package)) ; 1.
(method-2 (intern (format nil "~a-2" base-name) package)) ) ; 1.
`(progn
(defun ,helper-name () 'helper-called)
(defun ,method-1 () (,helper-name) '1-called)
(defun ,method-2 () (,helper-name) '2-called) )))
The following changes were made to your original definition -- the first change is the crucial one:
Interned each of computed symbol names into the same package as the base name using (intern ... package).
Introduced the variable package which is bound to the package of the supplied base-name symbol.
Changed let to let* to allow the newly introduced variable package to be referenced in subsequent variables.
Changed the prefix of the helper method to upper case to match the convention for normal Lisp symbols.
Use INTERN to turn the generated function name strings into symbols.