Lisp scope issue with setq? - scope

I'm a noob at lisp, have only been using it for two weeks or so...
I have some global variable declared with setq:
(setq myvar '(WHATEVER))
and a function that is supposed to modify whatever variable I tell it to:
(defun MYFUN (varname)
(setq varname '(POOP))
)
but when I make the call: (MYFUN 'myvar)
and check the value of myvar now it still is (WHATEVER) how do I make the changes that are made in MYFUN persist?

There is no such thing as "declaring a global variable with setq", there is only "set the value of a variable with setq" and if you're doing that in the top lexical environment, the results are amusingly under-defined.
If you look at what the variable varname contains, it may well be the list (poop).
Also, the "q" at the end of setq actually means "quoted" (that is, the setq special form will not evaluate the first (and third, and fifth...) argument, but will do so for the second (and fourth, and sixth...).
It was, historically, used as a convenience, where (set (quote var) value) was less convenient than (setq var value). However, (set var value) has exactly the same effect as (setf (symbol-value var) value) and you should use that.

You're setting the value of the local variable varname, not the global variable whose name it contains. To do what you want you need to use the symbol-value accessor to indirect through it to get the global value's variable.
(defun myfun (varname)
(setf (symbol-value varname) '(poop)))

EDIT: didn't notice this first:
You have local varname and global varname both in the scope of the function body. Local name shadows the global name. So, if you change the local name to var it should work the way you wrote (checked in SBCL 1.2.13). But consider the following stylistic corrections:
For global variables, please use ear-muffs * around the name, so it should be *myvar*. Global variables are special (there is a way to make them normal, but it is not necessarily a good idea). Special variables have dynamic scope, in contrast to lexical scope of normal variables.
The variable must be declared with defvar or defparameter. You can use setq for this but the compiler is going to complain that the variable is not defined. Also, with setq the variable is not going to be special.
For a variable *myvar* to appear special inside the body of the function, it either needs to be declared (with defvar or defparameter) before function definition, or it needs to be declared special in the body of the function with (declare (special *myvar*)) and then declared with defvar or defparameter.
Here is the code of possible combinations of declarations and respective outputs:
;; This is a model solution:
(defvar *myvar* 'a)
*MYVAR*
(defun foo (var)
(setq *myvar* var))
(foo 'b)
*myvar*
B
;; Not using DEFVAR or DEFPARAMETER
(setq myvar 'a)
A
(defun bar (var)
(setq myvar var))
;; The value of the global MYVAR is still changed
(bar 'b)
myvar
B
(defun show-myvar ()
myvar)
;; But MYVAR is not special
(let ((myvar 'z))
(show-myvar))
B
;; Also can assign value to undeclared variable
(defun bar2 (var)
(setq myvar-1 var))
BAR2
(setq myvar-1 'a)
A
;; And it works
(bar2 'b)
myvar-1
B
;; Finally: show special undeclared (yet) variable
(defun show-special ()
(declare (special *special-var*))
*special-var*)
(defvar *special-var* 'a)
*SPECIAL-VAR*
(let ((*special-var* 'z))
(show-special))
Z
;; The same but with SETQ: variable is still not special
(defun show-special-setq ()
(declare (special *special-var-setq*))
*special-var-setq*)
(setq *special-var-setq* 'a)
A
(let ((*special-var-setq* 'z))
(show-special-setq))
A

Related

Does SBCL for lisp handle scope differently? It does not seem to pass scope into called functions?

When using emacs or my android app I run
(defun big (num) (setf num2 5)(little num)))
(defun little (num)(+ num2 num))
Little happily accepts num2 but when I run it in my SBCL repl (with sublimetext3) it does not.
Is this correct?
What is a workaround without creating a global variable for num2?
I could just pass a second argument (little num num2)
But this wont work when I am trying to mapcar little over a list. Because I can only have one argument when mapcaring correct?
Please read ยง6. Variables from Practical Common Lisp.
Unlike Emacs Lisp, Common Lisp relies on lexical scope by default (Emacs Lisp is dynamic by default). Dynamic scope (i.e. indefinite scope and dynamic extent) is provided by declaring variables special, and by convention, they are written with asterisks around their names (named "earmuffs"), like *standard-output*. You use defparameter or defvar to declare those variables. Since it has a global effect, you should never use them from inside functions; likewise, your usage of setf is not defined in Common Lisp: no variable named num2 was declared previously in the scope; besides, even if it did, using a global/special variable for local variable is bad style.
Dynamic scope
With special variables, you can for example locally rebind the standard output: the new value is only visible while the code is inside the body of the let binding:
(let ((*standard-output* *error-output*))
(print "Stream redirection"))
By default, print writes to the stream bound to *standard-output*; here, the stream is locally bound to the one given by *error-output*. As soon as you escape the let, *standard-output* reverts to its previous value (imagine there is a stack).
Lexical scope
With lexical scope, your code can only access the bindings that are visible in the text surrounding your code (and the global scope), and the extent is indefinite: it is possible to access a binding (sometimes indirectly) even after the code returns from the let:
(let ((closure
(let ((count 0))
(lambda () (print (incf count))))))
(funcall closure)
(funcall closure))
;; prints:
;; 1
;; 2
The lambda expression creates a closure, which captures the variable named count. Every time you call it, it will increase the count variable and print it. If you evaluate the same code another time, you define another closure and create another variable, with the same name.
Mapcar
Because I can only have one argument when mapcaring correct?
Not exactly; the function called by mapcar should be able to accept at least as many elements as the number of lists that are given to it (and it should also not require more mandatory arguments):
(mapcar (lambda (x y) (* x y))
'(1 2 3)
'(0 3 6))
=> (0 6 18)
(mapcar #'list '(1 2) '(a b) '(+ /))
=> ((1 a +) (2 b /))
The function can also be a closure, and can use special variables.
... with a closure
(defun adder (x)
(lambda (y) (+ x y)))
(mapcar (adder 10) '(0 1 2))
=> (10 11 12)
The adder functions takes a number x and returns a closure which accepts a number y and returns (+ x y).
... with a special variable
If you prefer dynamic scope, use earmuffs and give it a meaningful name:
(defparameter *default-offset* 0)
... and define:
(defun offset (x)
(+ x *default-offset*))
You can then mapcar too:
(let ((*default-offset* 20))
(mapcar #'offset '(1 2 3)))
=> (21 22 23)
As said by jkiiski in comments, you can also declare special variables with (declare (special ...)) where you usually put declarations (when entering a let, a defun, ...). You could also use the special operator progv. This can be useful to have "invisible" variables that are only known by a set of functions to exchange information. You rarely need them.

How can I use setf on a dynamic variable effectively through a function call?

I am using dynamic variables, let's call one of them *x* with a value of 10.
I want to change its value through a function call by passing the variable's name as the parameter:
(defun change-value (varname)
(setf varname 20))
then calling (change-value *x*). If I understand correctly, varname takes local scope and therefore the setf has no effect outside change-value. So, *x* remains as 10 afterwards.
My question is, is there a way to make *x* equal to 20 through a function call similar to the above? I tried adding (proclaim '(special varname)) and (declare (special varname)) and they don't seem to do anything.
Oh, and defining a macro does more or less what I want, but I doubt this is good practice:
(defmacro change-value-macro (varname)
`(setf ,varname 20))
(change-value-macro *x*)
Defining
(defparameter *x* 10)
(defun change-value (varname) ; the argument name is misleading!
(setf varname 20))
and calling (change-value *x*) does not buy you anything because change-value is a function and you just passed it 10 as the argument; it has no idea that *x* is involved. So, what the function does is modify the local binding of the variable varname, changing it from 10 to 20 and returning the latter.
You need to pass the symbol (variable name) itself:
(defun change-value (varname)
(setf (symbol-value varname) 20))
and call it as (change-value '*x*) (note the quote mark ' before *x*).
This seems to work:
(defparameter *x* 'initial)
(defun change-dyn (variable value)
(setf (symbol-value variable) value))
(change-dyn '*x* 'final)

Want to access lexically defined functions using EVAL in CLISP

Why won't this piece of code work?
(setf x '(foo bar (baz)))
(labels
((baz () (print "baz here")))
(baz) ;works
(eval (third x))) ;fails with the below message
*** - EVAL: undefined function BAZ
I'm using GNU CLISP.
In Common Lisp, eval evaluates its argument in a null lexical environment, so your lexically bound function baz can't be found.
While the Common Lisp standard doesn't provide a portable way to access the lexical environment and invoke eval with it, your implementation might have this functionality. For example, in CLISP:
cs-user> (setf x '(foo bar (baz)))
(foo bar (baz))
cs-user> (labels ((baz () (print "baz here")))
(eval-env (third x) (the-environment)))
"baz here"
"baz here"
cs-user>
See geocar's answer for other approaches.
Because common lisp doesn't have special functions.
Check the description of EVAL:
Evaluates form in the current dynamic environment and the null lexical environment.
Since the lexical environment is empty, your baz function (defined by labels) isn't accessible. You'd think you could fix this by putting baz in the dynamic environment (you might want something like (declare (special baz)) or (declare (special (function baz))) or something like this) but alas: there's no way to do this.
You could simulate it yourself by creating:
(defvar baz* nil)
(defun baz (&rest args) (apply baz* args))
You then need to dynamically set baz* instead of using labels:
(setf x '(foo bar (baz)))
(let ((baz* (lambda () (print "baz here"))))
(eval (third x)))
The reason why is just some hard bits about optimisation leaking into the spec. Basically, every function-call would need some stubbing unless the compiler could prove that the function would never get defined dynamically swizzleable. That's hard to do efficiently, and it's not something most CL programmers ever did, so the spec-writers simply forbade it.
As you can see, and as with most things in CL, you can easily get it yourself if you need it. However. Given that most CL programmers never do this, you may want to re-examine why you're trying to do things this way.

String converted to a function command for global-set-key (elisp)

I would like to call global-set-key in a function, giving it arguments, to create global-set-keys.
(defun global-setter (arg1 arg2)
(global-set-key arg1 '(concat "example" arg1 arg2))
)
(global-setter "*" "^")
This should create the binding that when pressing *, the function example-*^ should be called.
I can't figure out how to get the string to be passed as a function / command name. What am I doing wrong?
So far I tried combinations of `',#, (intern), (eval), (function) but I have no idea what I should be doing.
One reason your code doesn't work is because you quoted the (concat ..) expression so it's never evaluated. And global-set-key expects a lambda or a symbol.
You can construct a symbol using intern, then provide the symbol to set-key:
(defun my-test () (interactive) (message "ok"))
(global-set-key "\C-c!" (intern (concat "my" "-" "test")))
Note that any function called via global-set-key and variants must be interactive.
Use lexical-let to define a closure, an anonymous function that references values from the environment in which it was defined:
(defun global-setter (arg1 arg2)
(lexical-let ((arg1 arg1) (arg2 arg2))
(global-set-key arg1 (lambda ()
(interactive)
(concat "example" arg1 arg2)))))
Emacs 24 natively supports lexical binding and closures, so lexical-let is no longer necessary:
(defun global-setter (arg1 arg2)
(global-set-key arg1 (lambda ()
(interactive)
(concat "example" arg1 arg2))))
For this to work, be sure to set lexical-binding to t in your .emacs and add this to the end of the file to ensure lexical-binding is used for byte-compilation:
;; Local Variables:
;; lexical-binding: t
;; End:

getting standard input and storing it as a string in lisp

I realize this is probably a really stupid question but i have no idea why this isnt working and i pretty much gave up. basically i tried:
(setq answer (string (read)))
and
(setq answer 0)
(format answer "~s" (read))
and
(setq answer (read))
when i try to evaluate
(if (stringp answer)
(princ "works")
(princ "failed"))
on any of the above tries it always comes out failed.
what am i doing wrong?
Or you could just do:
(setq answer (read-line))
That gives you a string right there.
[1]> (setq answer (read))
3
3
[2]> (type-of answer)
(INTEGER 0 16777215)
[3]> (setq answer (read-line))
3
"3"
[4]> (type-of answer)
(SIMPLE-BASE-STRING 1)
[5]>
Start a fresh REPL, then try checking the return value of each of your steps:
T1> (read)
foo
FOO
T1> (read)
1
1
T1> (type-of (read))
foo
SYMBOL
T1> (type-of (read))
1
BIT
Now note, that STRING won't work on all input types:
T1> (string 'foo)
"FOO"
T1> (string 1)
Also note that, unlike setq, (format foo ...) won't set foo, but write to it, if it's a stream or a string with a fill-pointer. Take a look at its Documentation, and you'll see:
format destination control-string
&rest args => result
[...]
destination---nil, t, a stream, or a
string with a fill pointer.
[...]
format is useful for producing nicely
formatted text, producing good-looking
messages, and so on. format can
generate and return a string or output
to destination.
If destination is a string, a stream,
or t, then the result is nil.
Otherwise, the result is a string
containing the `output.'
Try it like this:
T1> (setq *answer*
(with-output-to-string (s)
(format s "~s" (read))))
1
"1"
T1> *answer*
"1"
Or like this:
T1> (setq *answer* (make-array 20 :element-type 'character :fill-pointer 0))
""
T1> (format *answer* "~s" (read))
1
NIL
T1> *answer*
"1"
Those are the only relevant errors I could find in your code. This definitely returns "works" in every conforming CL (you could also use prin1-to-string):
T1> (defvar *answer*)
*ANSWER*
T1> (setq *answer* (format nil "~s" (read)))
1
"1"
T1> (if (stringp *answer*)
(princ "works")
(princ "failed"))
works
"works"
Unless you are in a messed-up package (try (in-package cl-user) before evaluating your code), or redefined basic functionality, this will work. Give some more exact error descriptions, if it still won't.
ED:
Having read Bill's answer, who correctly pointed at read-line as a shorter solution, I should maybe mention that I didn't try to show the best, most succinct, or most idiomatic approaches in my answer, and that those will vary depending on what you are really trying to do. (The shortest possible solution would have been "works" :) They are just examples that should help explaining why your code failed.
Another thing I forgot to say is that you should keep in mind, that toplevel setqs on variables not defined with defvar or defparameter are generally to be avoided in anything but dabbling at the REPL, since the consequences are undefined. Also, those variables are, by convention, wrapped in asterisks (also called earmuffs) in order to prevent bugs caused by confusing specials with lexically scoped variables.

Resources