How to find variable in package using string and change it? - package

I have package with some variables:
(in-package #:pack)
(defparameter *a* "foo")
(defparameter *b* "bar")
Variables *a* and *b* are exported.
My goal is change this variables using strings ("*a*" and "*b*")
I can find these variables with intern function
(symbol-value (intern (string-upcase "*a*") :pack)) ;; return *a* symbol
(symbol-name (intern (string-upcase "*a*") :pack)) ;; return "foo"
But if I trying to change symbol with
(setf (symbol-name (intern (string-upcase "*a*") :pack)) "baz")
I've got an error:
The function (COMMON-LISP:SETF COMMON-LISP:SYMBOL-NAME) is undefined.
[Condition of type UNDEFINED-FUNCTION]
How can I change these variables?

As pointed in a comment #jkiiski, there is function in common lisp used to find symbols in a package:
find_symbol:
Function FIND-SYMBOL
Syntax:
find-symbol string &optional package => symbol, status
Then the other important thing is take a look at the answer here for understanding the difference between variables and symbols in common lisp.
And the function set, setq and setf from common lisp hypersec
set changes the contents of the value cell of symbol to the given
value.
setq(setq var1 form1 var2 form2 ...) is the simple variable assignment
statement of Lisp. First form1 is evaluated and the result is stored
in the variable var1, then form2 is evaluated and the result stored in
var2, and so forth. setq may be used for assignment of both lexical
and dynamic variables.
(setf place newvalue) expands into an update form that stores the
result of evaluating newvalue into the location referred to by place.
Some place forms involve uses of accessors that take optional
arguments. Whether those optional arguments are permitted by setf, or
what their use is, is up to the setf expander function and is not
under the control of setf. The documentation for any function that
accepts &optional, &rest, or ..... key arguments and that claims to be
usable with setf must specify how those arguments are treated.
So joining all this things we can have this code:
(defpackage :pack
(:use :cl) ;; You must import this line in order to use functions from cl package like setf
(:export :*a*
:*b*))
(in-package :pack)
(defparameter *a* "foo")
(defparameter *b* "bar")
Now lets explore the variables
CL-USER> pack:*a*
"foo"
CL-USER> pack:*b*
"bar"
Then we can find the symbol a (note that common lisp is case insensitive if you don't use || for naming symbols)
CL-USER> (find-symbol "*A*" :pack)
PACK:*A*
:EXTERNAL
So here, there is nothing unexpected exists symbol a and it is external to the package pack
then let's change the value wit set we can directly change the value but with setf we need a place, a pointer in the case of common lisp a symbol have different pointers in this case the important for us is symbol-value. so for changing that we can proceed as follow:
CL-USER> (set (find-symbol "*A*" :pack) "baz")
"baz"
CL-USER> pack:*a*
"baz"
CL-USER> (setf (symbol-value (find-symbol "*A*" :pack)) "buzz" )
"buzz"
CL-USER> pack:*a*
"buzz"
Hope this helps.

Related

Non-existent hy macros runs assertions, but fails appropriately with everything else

In the following code:
(eval-and-compile (import os hy))
(eval-and-compile (import pathlib [Path]))
; (defmacro with-cwd [dir #* body]
; (setv cwd (hy.gensym))
; `(let [ ~cwd (.cwd Path) ]
; (try (.chdir os ~dir)
; ~#body
; (finally (.chdir os ~cwd)))))
(setv cookies (/ (.cwd Path) "cookies"))
; This fails with an `AssertionError'
(with-cwd cookies (assert (= (.cwd Path) cookies)))
; This fails with a `NameError'
(with-cwd cookies (.cwd Path))
Similarly, any functions or macros depending on the missing macro errors out in the same way, and if, for example, I'm importing or requiring a function or macro that depends on the missing macro, the same thing happens; basically, I have to import or require a function or macro as well as its dependencies manually.
Is this a bug, or am I missing something about the order of Python / Hy assertions? I expected the first case to fail with a NameError as well.
This is a documented quirk:
Like many programming languages, but unlike Python, Hy doesn't guarantee in all cases the order in which function arguments are evaluated. More generally, the evaluation order of the child models of a hy.models.Sequence is unspecified. For example, (f (g) (h)) might evaluate (part of) (h) before (g), particularly if f is a function whereas h is a macro that produces Python-level statements. So if you need to be sure that g is called first, call it before f.
In this case, the assert statement has gotten pulled out of the function call ((with-cmd …) being a function call, since there is no macro named with-cmd) and evaluated before the symbol with-cmd itself.

:EXPORT from Package in Common Lisp

I have defined a package like the following:
(defpackage :thehilariouspackageofamirteymuri
(:nicknames ampack amir teymuri)
(:use common-lisp)
(:export say-hi-to))
(in-package :amir)
(defun say-hi ()
"Docstring"
"Hello")
(defun say-hi-to (who)
(concatenate 'string (say-hi) " " who " from " (package-name *package*) "!"))
Now changing to the package also the #'say-hi is accessible:
(in-package :amir)
(say-hi) ; -> "Hello"
(say-hi-to "World") ; -> "Hello World from THEHILARIOUSPACKAGEOFAMIRTEYMURI!"
Isn't the export keyword telling to make things external for the package? Why is the non-external #'say-hi also exported?
Since you are using again (in-package :amir) the following forms are evaluated in that package, so that you can use all the function defined in it. To check which definitions are exported, you should switch to a different package.
Let’s try the standard package CL-USER:
AMIR> (in-package :cl-user)
#<Package "COMMON-LISP-USER">
CL-USER> (say-hi)
Undefined function SAY-HI called with arguments ("world") ; as expected, but...
CL-USER> (say-hi-to "world")
Undefined function SAY-HI-TO called with arguments ("world") ; ops!!
CL-USER> (amir:say-hi-to "world)
"Hello world from COMMON-LISP-USER!"
CL-USER> (amir:say-hi)
Reader error: No external symbol named "SAY-HI" in package #<Package "THEHILARIOUSPACKAGEOFAMIRTEYMURI"> .
The reason is that exporting a symbol does not mean that we can use it without qualiyfing its package. As you can see, however, only symbols exported from a packgage can be used with “:”. If you want to use the symbol without the package name as prefix, you must import it before.
So, let’s start again.
CL-USER> (defpackage :another-package (:use :amir))
#<Package "ANOTHER-PACKAGE">
CL-USER> (in-package :another-package)
#<Package "ANOTHER-PACKAGE">
ANOTHER-PACKAGE> (say-hi-to "world")
"Hello world from ANOTHER-PACKAGE!"
ANOTHER-PACKAGE> (say-hi)
Undefined function SAY-HI called with arguments ()
Inside ANOTHER-PACKAGE you can now use the exported symbol without qualifications.
In general, exporting and importing symbols in packages in Common Lisp is not so intuitive, and a good description of all the intricacies of packages can be found at the link cited in the other answer.
Check the difference without changing the current package. You will find more information e.g. here

Suppressing Symbol Package Prefixes (Common Lisp)

When printing out object names which are interned in one package, but referenced from another package, the print name will include the full package name. For example, the following interaction interns the symbol X in PKG1, and prints its value from CL-USER:
* *package*
#<PACKAGE "COMMON-LISP-USER">
* (defpackage :pkg1 (:use :cl))
#<PACKAGE "PKG1">
* (in-package :pkg1)
#<PACKAGE "PKG1">
* (defvar x '(a b c))
X
* (in-package :cl-user)
#<PACKAGE "COMMON-LISP-USER">
* pkg1::x
(PKG1::A PKG1::B PKG1::C)
Sometimes for diagnostic/debugging reasons, I would like to printout external symbols without their package prefixes. In this case the printout would then look like (A B C). For complicated or nested objects where you know what the names mean, the package prefixes can make the printout hard to read, especially if there are multiple packages. Can the prefixes be temporarily suppressed for printout?
No, but you can elide the prefixes of one package by temporarily binding *package* to it for the printout.
Example:
(let ((*package* (find-package :pkg1)))
(print pkg1:*x*))
Since *package* is globally dynamic, this affects everything called inside (i. e. in the dynamic extent of its invocation) this let form but doesn't affect anything outside.

Common Lisp appending package name to quoted keys in macros

I noticed the following behavior in Common Lisp (at least using SBCL), which I was able to reduce it to the following:
Suppose I have the following Macro:
(defpackage "MY-TEST"
(:use "COMMON-LISP")
(:export :appended
:not-appended))
(in-package :MY-TEST)
(defmacro not-appended ()
`(list ':type 'array))
(defmacro appended ()
`(list ':type 'something-else))
The following is the output:
* (my-test:not-appended)
(:TYPE ARRAY)
* (my-test:appended)
(:TYPE MY-TEST::SOMETHING-ELSE)
Notice that in the second macro, the namespace is preceding the "SOMETHING-ELSE".
Questions:
Why is t the case that they differ? Honestly I was expecting the behavior of the "not-appended" macro. Is that because "array" is somehow known to Common Lisp?
If yes, then where can I find the other known keywords?
Note that this is fully unrelated to macros and is an effect of packages, symbols and how symbols are printed:
The package `MY-TEST':
CL-USER 2 > (defpackage "MY-TEST"
(:use "COMMON-LISP")
(:export :appended
:not-appended))
#<The MY-TEST package, 0/16 internal, 2/16 external>
Making the package the current package by calling in-package:
CL-USER 3 > (in-package :MY-TEST)
#<The MY-TEST package, 0/16 internal, 2/16 external>
Let's compute a list of the symbols array and foo. See how the REPL prints it as (ARRAY FOO) because both symbols are accessible in package MY-TEST.
MY-TEST 4 > (list 'array 'foo)
(ARRAY FOO)
Making CL-USER the current package:
MY-TEST 5 > (in-package :cl-user)
#<The COMMON-LISP-USER package, 151/256 internal, 0/4 external>
Now let's get the second last value and see how the REPL prints it:
CL-USER 6 > **
(ARRAY MY-TEST::FOO)
ARRAY is printed without package prefix, because it is the same symbol from the package COMMON-LISP (which was used in the package MY-TEST). FOO is printed with the package prefix MY-TEST, because it is an internal symbol in that package - it was interned there, because then the current package was MY-TEST. There are two colons, because the symbol FOO is not exported from the package MY-TEST and it is also not imported into the package CL-USER.
The package "CL" and "CL-USER" contain all the symbols from the programming language Common Lisp - thus importing "CL" into your own package makes all of those symbols available in that package, too.
CL-USER 7 > (let ((l '()))
(do-symbols (sym (find-package "CL") l)
(pushnew sym l)))
(MAKE-ARRAY INVOKE-DEBUGGER STRING-TRIM WILD-PATHNAME-P UNREAD-CHAR RESTART-BIND ...

Common Lisp package definition

In Common Lisp package definition, what is the difference between
(defpackage #:foo
(:use :cl)
(:export #:bar
#:baz))
(in-package #:foo)
and
(defpackage :foo
(:use :cl)
(:export :bar
:baz))
(in-package :foo)
I mean. When I have to use the "#" character? All these symbols are uninternerd, right?
:foo is the syntax for a keyword symbol, and #:foo is the syntax for an uninterned symbol. When a symbol is used primarily to get at the string that is its name (as in defpackage and in-package), I prefer to use uninterned symbols.
Here are the other options:
use a keyword symbol; I don't like how this interns keyword symbols that show up in apropos and other places
use a string; I don't like how this gratuitously breaks Allegro's "modern" mode
use a plain symbol; I don't like how this both interns a symbol, and how it interns it in a potentially random package
Which style you or anyone else uses is a matter of taste.

Resources