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

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.

Related

Lisp scope issue with setq?

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

Pass an object argument to a macro

I encounter errors when passing an object argument to a macro. Must I quote the argument, put it in a list, or not quote it?
I wish to use Clozure Common Lisp to generate and run multiple processes in parallel using a read-write-lock to control data output to another process. With-write-lock is a macro that waits until the given lock is available for write access, then executes its body with the lock held. However, I get errors no matter how I try to pass the lock to with-write-lock. I'm having trouble I think because I fail to understand how to pass a lock object to the with-write-lock macro. If I bind the lock to a symbol I get destructuring errors:
(let ((l (make-read-write-lock)))
(with-write-lock l (1+ 1)))
==>
> Error: L can't be destructured against the lambda list (LOCK), because it is not a proper list.
While executing: (:INTERNAL CCL::NX1-COMPILE-LAMBDA), in process Listener(4).
but if I pass the call to make-read-write-lock as the lock argument to with-write-lock then I get an undeclared free variable error:
(with-write-lock (make-read-write-lock) (1+ 1))
==>
;Compiler warnings for "/Users/frank/Documents/Lisp/threaded/act-parallel.lisp" :
;In an anonymous lambda form at position 18: Undeclared free variable MAKE-READ-WRITE-LOCK
Error: Unbound variable: MAKE-READ-WRITE-LOCK
While executing: #, in process Listener(4).
Am I failing because I misunderstand how to pass an object to a macro or am I going awry because or something more particular to with-write-lock?
Here's the with-write-lock macro that comes with Clozure Common Lisp (macros.lisp):
(defmacro with-write-lock ((lock) &body body)
(let* ((locked (gensym))
(p (gensym)))
`(with-lock-context
(let* ((,locked (make-lock-acquisition))
(,p ,lock))
(declare (dynamic-extent ,locked))
(unwind-protect
(progn
(write-lock-rwlock ,p ,locked)
,#body)
(when (lock-acquisition.status ,locked) (unlock-rwlock ,p)))))))
The lambda list for that macro is destructuring its arguments.
((lock) &body body)
Means that it wants the first argument as a list which contains the lock and then the body form. This is a pretty standard macro argument list in CL, you can use it like this:
(with-write-lock (lock)
..... body forms ....)
So your examples would be
(let ((l (make-read-write-lock)))
(with-write-lock (l) (1+ 1)))
And:
(with-write-lock ((make-read-write-lock)) (1+ 1))
respectively. Note the extra parens around the first argument.
For similar macros see with-open-file or destructuring-bind
(with-open-file ("path/to/file" :open :args)
.... body ...)
(destructuring-bind (one two three) '(1 2 3)
.... body forms ...)

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.

Update the whole structure

Suppose I have some function which returns a struct:
(struct layer (points lines areas))
(define (build-new-layer height)
...
(layer list-a list-b list-c))
I want to keep track of the last returned result something like:
(define top-side (build-new-layer 0)) ; store the first result
...
(set! top-side (build-new-layer 0.5)) ; throw away the first result and store the new one
However, for that particular code I get the error:
set!: assignment disallowed;
cannot modify a constant
constant: top-side
Please, tell me what would be the right way to do what I want
What language are you using? it seems it's a matter of configuration, because in principle what you're doing should work. Go to the "choose language" window (Ctrl+L in Windows), click on "show details" and see if one of the options of the language currently in use disallows redefinition of variables. Alternatively, try using a different language.
Depending on where exactly you're going to use the stored result (I can't tell from the code in the question), you could pass it around as function parameters, in such a way that using a global variable is no longer necessary. This might be a better idea, relying on global state and mutation (the set! operation) is discouraged in Scheme.
If you always want to keep around the last layer, then you might prefer setting the last-layer every time one is built. Like this.
(define last-layer #f)
(define build-new-layer
(let ((save-layer #f))
(lambda (height)
(let ((new-layer (layer list-a ...)))
(set! last-layer save-layer)
(set! save-layer new-layer)
new-layer))))
Note: if the real problem is the 'constant-ness' of last-layer then build yourself a little abstraction as:
(define-values (last-layer-get last-layer-set!)
(begin
(define last-layer-access
(let ((last-layer #f))
(lambda (type . layer)
(case type
((get) last-layer)
((set) (set! last-layer (car layer)))))))
(values (lambda () (last-layer-access 'get))
(lambda (layer) (last-layer-access 'set layer))))

Resources