Efficient evaluation of spliced lists with a recurring argument - lisp

I want to recur through a list of slot names of classes, the same slot names for two classes ((current-trial *exp*) & (previous *exp*) refer to instances of the same class). On each recursion, I want to evaluate the slot name so that the value of that slot of that instance may be got and set. The code below meets that expectation, but I worry about relying upon eval because it's slow and doesn't allow for lexical context (Graham, 1996). What would be alternative formulations that would be efficient and allow for lexical context?
(dolist (a '(letter number font color height))
(eval
`(when (eq (,a (current-trial *exp*))
(,a (previous *exp*)))
(setf (,a (current-trial *exp*))
(random-not-item
(,a (current-trial *exp*))
(,a *exp*))))))

Since these are slot names, you can use slot-value:
(dolist (a '(letter number font color height))
(when (eq (slot-value (current-trial *exp*) a)
(slot-value (previous *exp*) a))
(setf (slot-value (current-trial *exp*) a)
(random-not-item
(slot-value (current-trial *exp*) a)
(slot-value *exp* a)))))

Related

Is there any way to see the implementations of built-in macros in Common Lisp?

Common Lisp built-in functions are probably implemented in C. But I imagine macros are implemented in lisp (sorry if I'm wrong about any of two sentences). Is there any way (through some function or some macro) to see the implementations of built-in macros in Common Lisp? I'm using CLisp.
The ability to inspect function and macro definitions is a feature of your development environment. These days it is typical to use SLIME or SLY with emacs as the basis of a Lisp development environment. I personally use SLIME, but I have heard good things about SLY, too.
In SLIME you can invoke slime-edit-definition (either by keying M-x slime-edit-definition or by using the keybinding M-.) to visit a definition for the symbol under the cursor in a source file. This works both when editing in a source file, or from the REPL. This feature is extremely useful when you want to inspect some library code you are working with, but you can also view a lot of built-in definitions this way. You can even jump to a new definition from a new symbol found in whatever definition you are currently inspecting.
After you are done looking at a definition, you can use M-x slime-pop-find-definition-stack, or the easier to remember keybinding M-, (M-* will also work), to back out through the previously viewed definitions, eventually returning to your starting point.
Here is an example, in SBCL:
CL-USER> with-open-file[press M-.]
(Note that the "[press M-.]" above is not typed, but only meant to remind what action is taken here). With the cursor on or right after the symbol with-open-file, press M-. to see the definition:
(sb-xc:defmacro with-open-file ((stream filespec &rest options)
&body body)
(multiple-value-bind (forms decls) (parse-body body nil)
(let ((abortp (gensym)))
`(let ((,stream (open ,filespec ,#options))
(,abortp t))
,#decls
(unwind-protect
(multiple-value-prog1
(progn ,#forms)
(setq ,abortp nil))
(when ,stream
(close ,stream :abort ,abortp)))))))
This time after keying M-. SLIME gives a choice of definitions to view:
CL-USER> and[press M-.]
Displayed in an emacs buffer:
/path-to-source/sbcl-2.0.4/src/code/macros.lisp
(DEFMACRO AND)
/path-to-source/sbcl-2.0.4/src/pcl/ctypes.lisp
(DEFINE-METHOD-COMBINATION AND)
We want to see the macro definition, so move the cursor to the line showing (DEFMACRO AND), and the following definition is displayed:
;; AND and OR are defined in terms of IF.
(sb-xc:defmacro and (&rest forms)
(named-let expand-forms ((nested nil) (forms forms) (ignore-last nil))
(cond ((endp forms) t)
((endp (rest forms))
(let ((car (car forms)))
(cond (nested
car)
(t
;; Preserve non-toplevelness of the form!
`(the t ,car)))))
((and ignore-last
(endp (cddr forms)))
(car forms))
;; Better code that way, since the result will only have two
;; values, NIL or the last form, and the precedeing tests
;; will only be used for jumps
((and (not nested) (cddr forms))
`(if ,(expand-forms t forms t)
,#(last forms)))
(t
`(if ,(first forms)
,(expand-forms t (rest forms) ignore-last))))))
There is more stuff here, since you are now actually in the source file that contains the definition for and; if you scroll down a bit you can also find the definition for or.
A lot of SBCL functions are written in Lisp; SBCL has a very high-quality compiler, so a lot of stuff that you might otherwise expect to be written in C can be written in Lisp without loss of performance. Here is the definition for the function list-length:
CL-USER> list-length[press M-.]
(defun list-length (list)
"Return the length of the given List, or Nil if the List is circular."
(do ((n 0 (+ n 2))
(y list (cddr y))
(z list (cdr z)))
(())
(declare (type fixnum n)
(type list y z))
(when (endp y) (return n))
(when (endp (cdr y)) (return (+ n 1)))
(when (and (eq y z) (> n 0)) (return nil))))
The same thing can be done when using CLISP with SLIME. Here is with-open-file as defined in CLISP:
CL-USER> with-open-file[press M-.]
(defmacro with-open-file ((stream &rest options) &body body)
(multiple-value-bind (body-rest declarations) (SYSTEM::PARSE-BODY body)
`(LET ((,stream (OPEN ,#options)))
(DECLARE (READ-ONLY ,stream) ,#declarations)
(UNWIND-PROTECT
(MULTIPLE-VALUE-PROG1
(PROGN ,#body-rest)
;; Why do we do a first CLOSE invocation inside the protected form?
;; For reliability: Because the stream may be a buffered file stream,
;; therefore (CLOSE ,stream) may produce a disk-full error while
;; writing the last block of the file. In this case, we need to erase
;; the file again, through a (CLOSE ,stream :ABORT T) invocation.
(WHEN ,stream (CLOSE ,stream)))
(WHEN ,stream (CLOSE ,stream :ABORT T))))))
But, many CLISP functions are written in C, and those definitions are not available to inspect in the same way as before:
CL-USER> list-length[press M-.]
No known definition for: list-length (in COMMON-LISP-USER)

List gensym symbol not evaluating inside macro

I'm trying to write a macro that takes a list of variables and a body of code and makes sure variables revert to their original values after body of code is executed (exercise 10.6 in Paul Graham's ANSI Common Lisp).
However, I'm unclear on why my gensym evaluates as I expect it to in one place, but not another similar one (note: I know there's a better solution to the exercise. I just want to figure out why the difference in evaluation).
Here's the first definition where the lst gensym evaluates to a list inside of the lambda passed to the mapcar:
(defmacro exec-reset-vars-1 (vars body)
(let ((lst (gensym)))
`(let ((,lst ,(reduce #'(lambda (acc var) `(cons ,(symbol-value var) ,acc))
vars
:initial-value nil)))
,#body
,#(mapcar #'(lambda (var) `(setf ,var (car ,lst)))
vars))))
But while it works exactly as I expect it to, it's not a correct solution to the exercise because I'm always grabbing the first element of lst when trying to reset values. I really want to map over 2 lists. So now I write:
(defmacro exec-reset-vars-2 (vars body)
(let ((lst (gensym)))
`(let ((,lst ,(reduce #'(lambda (acc var) `(cons ,(symbol-value var) ,acc))
vars
:initial-value nil)))
,#body
,#(mapcar #'(lambda (var val) `(setf ,var ,val))
vars
lst))))
But now I get an error that says #:G3984 is not a list. If I replace it with (symbol-value lst) I get an error saying variable has no value. But why not? Why does it have a value inside of the setf in lambda, but not as an argument passed to mapcar?
At macroexpansion time you try to map over the value of lst, which is a symbol at that time. So that makes no sense.
Trying to get symbol value also makes no sense, since lst's bindings are lexical and symbol-value is not a way to access that. Other bindings are not available at that time.
Clearly lst has a value at macroexpansion time: a symbol. This is what you see inside the lambda.
You need to make clear what values are computed at macroexpansion time and which at runtime.
An advice about naming:
lst is a poor name in Lisp, use list
the name lst makes no sense, since its value is not a list, but a symbol. I'd call it list-variable-symbol. Looks long, doesn't it? But it is much clearer. You would now that it is a symbol, used as the name for a variable holding lists.
I'm pretty sure you are overthinking it. Imagine this:
(defparameter *global* 5)
(let ((local 10))
(with-reset-vars (local *global*)
(setf *global* 20)
(setf local 30)
...))
I imagine the expansion is as easy as:
(defparameter *global* 5)
(let ((local 10))
(let ((*global* *global*) (local local))
(setf *global* 20)
(setf local 30)
...)
(print local)) ; prints 10
(print *global*) ; prints 5
let does the reset on it's own so you see that the macro should be very simple just making shadow bindings with let, unless I have misunderstood the assignment.
Your overly complicated macros does pretty bad things. Like getting values of global symbols compile time, which would reset them to the time the function that used this instead of before the body.

SICP: Can or be defined in lisp as a syntactic transformation without gensym?

I am trying to solve the last part of question 4.4 of the Structure and Interpretation of computer programming; the task is to implement or as a syntactic transformation. Only elementary syntactic forms are defined; quote, if, begin, cond, define, apply and lambda.
(or a b ... c) is equal to the first true value or false if no value is true.
The way I want to approach it is to transform for example (or a b c) into
(if a a (if b b (if c c false)))
the problem with this is that a, b, and c would be evaluated twice, which could give incorrect results if any of them had side-effects. So I want something like a let
(let ((syma a))
(if syma syma (let ((symb b))
(if symb symb (let ((symc c))
(if (symc symc false)) )) )) )
and this in turn could be implemented via lambda as in Exercise 4.6. The problem now is determining symbols syma, symb and symc; if for example the expression b contains a reference to the variable syma, then the let will destroy the binding. Thus we must have that syma is a symbol not in b or c.
Now we hit a snag; the only way I can see out of this hole is to have symbols that cannot have been in any expression passed to eval. (This includes symbols that might have been passed in by other syntactic transformations).
However because I don't have direct access to the environment at the expression I'm not sure if there is any reasonable way of producing such symbols; I think Common Lisp has the function gensym for this purpose (which would mean sticking state in the metacircular interpreter, endangering any concurrent use).
Am I missing something? Is there a way to implement or without using gensym? I know that Scheme has it's own hygenic macro system, but I haven't grokked how it works and I'm not sure whether it's got a gensym underneath.
I think what you might want to do here is to transform to a syntactic expansion where the evaluation of the various forms aren't nested. You could do this, e.g., by wrapping each form as a lambda function and then the approach that you're using is fine. E.g., you can do turn something like
(or a b c)
into
(let ((l1 (lambda () a))
(l2 (lambda () b))
(l3 (lambda () c)))
(let ((v1 (l1)))
(if v1 v1
(let ((v2 (l2)))
(if v2 v2
(let ((v3 (l3)))
(if v3 v3
false)))))))
(Actually, the evaluation of the lambda function calls are still nested in the ifs and lets, but the definition of the lambda functions are in a location such that calling them in the nested ifs and lets doesn't cause any difficulty with captured bindings.) This doesn't address the issue of how you get the variables l1–l3 and v1–v3, but that doesn't matter so much, none of them are in scope for the bodies of the lambda functions, so you don't need to worry about whether they appear in the body or not. In fact, you can use the same variable for all the results:
(let ((l1 (lambda () a))
(l2 (lambda () b))
(l3 (lambda () c)))
(let ((v (l1)))
(if v v
(let ((v (l2)))
(if v v
(let ((v (l3)))
(if v v
false)))))))
At this point, you're really just doing loop unrolling of a more general form like:
(define (functional-or . functions)
(if (null? functions)
false
(let ((v ((first functions))))
(if v v
(functional-or (rest functions))))))
and the expansion of (or a b c) is simply
(functional-or (lambda () a) (lambda () b) (lambda () c))
This approach is also used in an answer to Why (apply and '(1 2 3)) doesn't work while (and 1 2 3) works in R5RS?. And none of this required any GENSYMing!
In SICP you are given two ways of implementing or. One that handles them as special forms which is trivial and one as derived expressions. I'm unsure if they actually thought you would see this as a problem, but you can do it by implementing gensym or altering variable? and how you make derived variables like this:
;; a unique tag to identify special variables
(define id (vector 'id))
;; a way to make such variable
(define (make-var x)
(list id x))
;; redefine variable? to handle macro-variables
(define (variable? exp)
(or (symbol? exp)
(tagged-list? exp id)))
;; makes combinations so that you don't evaluate
;; every part twice in case of side effects (set!)
(define (or->combination terms)
(if (null? terms)
'false
(let ((tmp (make-var 'tmp)))
(list (make-lambda (list tmp)
(list (make-if tmp
tmp
(or->combination (cdr terms)))))
(car terms)))))
;; My original version
;; This might not be good since it uses backquotes not introduced
;; until chapter 5 and uses features from exercise 4.6
;; Though, might be easier to read for some so I'll leave it.
(define (or->combination terms)
(if (null? terms)
'false
(let ((tmp (make-var 'tmp)))
`(let ((,tmp ,(car terms)))
(if ,tmp
,tmp
,(or->combination (cdr terms)))))))
How it works is that make-var creates a new list every time it is called, even with the same argument. Since it has id as it's first element variable? will identify it as a variable. Since it's a list it will only match in variable lookup with eq? if it is the same list, so several nested or->combination tmp-vars will all be seen as different by lookup-variable-value since (eq? (list) (list)) => #f and special variables being lists they will never shadow any symbol in code.
This is influenced by eiod, by Al Petrofsky, which implements syntax-rules in a similar manner. Unless you look at others implementations as spoilers you should give it a read.

Common Lisp: Method to minimize code duplication when defining setf expanders

Triggered from this question about setf expanders: defining setf-expanders in Common Lisp
When writing setf expanders for user-defined getters, I commonly find that there is code duplication in the getter and setter, as far as how the property is retrieved. For example:
CL-USER>
(defun new-car (lst)
(car lst))
NEW-CAR
CL-USER>
(defun (setf new-car) (new-value lst)
(setf (car lst) new-value))
(SETF NEW-CAR)
CL-USER>
(defparameter *lst* (list 5 4 3))
*LST*
CL-USER>
*lst*
(5 4 3)
CL-USER>
(setf (new-car *lst*) 3)
3
CL-USER>
*lst*
(3 4 3)
CL-USER>
Note how the (car lst) form, the actual accessor that already has a setf expander defined, is in both defuns. This has always annoyed me somewhat. It would be nice to be able to say on the first defun, 'hey, I'm defining a defun that's a getter, but I also want it to have a typical setf expander'.
Is there any way with the common lisp standard to express this? Has anyone else worried about this issue, and defined a macro that does this?
To be clear, what I'd like here is a way to define a getter and typical setter, where the way that the getter compiles down to common lisp forms that already have setters ((car lst), e.g.) is written only once in the code.
I also understand there are times where you wouldn't want to do this, b/c the setter needs to perform some side effects before setting the value. Or it's an abstraction that actually sets multiple values, or whatever. This question is less relevant in that situation. What I'm talking about here is the case where the setter does the standard thing, and just sets the place of the getter.
What you want can be achieved with the use of macros.
(defmacro define-place (name lambda-list sexp)
(let ((value-var (gensym)))
`(progn
(defun ,name ,lambda-list
,sexp)
(defun (setf ,name) (,value-var ,#lambda-list)
(setf ,sexp ,value-var)))))
(define-place new-chr (list)
(car list))
More information on macros can be found in Peter Seibel's book, Practical Common Lisp. Chapter 10 of Paul Graham's book "ANSI Common Lisp" is another reference.
Note how the (car lst) form, the actual accessor that already has a setf expander defined, is in both defuns.
But that's only apparently true before macro expansion. In your setter, the (car lst) form is the target of an assignment. It will expand to something else, like the call to some internal function that resembles rplaca:
You can do a similar thing manually:
(defun new-car (lst)
(car lst))
(defun (setf new-car) (new-value lst)
(rplaca lst new-value)
new-value)
Voilà; you no longer have duplicate calls to car; the getter calls car, and the setter rplaca.
Note that we manually have to return new-value, because rplaca returns lst.
You will find that in many Lisps, the built-in setf expander for car uses an alternative function (perhaps named sys:rplaca, or variations thereupon) which returns the assigned value.
The way we generally minimize code duplication when defining new kinds of places in Common Lisp is to use define-setf-expander.
With this macro, we associate a new place symbol with two items:
a macro lambda list which defines the syntax for the place.
a body of code which calculates and returns five pieces of information, as five return values. These are collectively called the "setf expansion".
The place-mutating macros like setf use the macro lambda list to destructure the place syntax and invoke the body of code which calculates those five pieces. Those five pieces are then used to generate the place accessing/updating code.
Note, nevertheless, that the last two items of the setf expansion are the store form and the access form. We can't get away from this duality. If we were defining the setf expansion for a car-like place, our access form would invoke car and the store form would be based on rplaca, ensuring that the new value is returned, just like in the above two functions.
However there can exist places for which a significant internal calculation can be shared between the access and the store.
Suppose we were defining my-cadar instead of my-car:
(defun new-cadar (lst)
(cadar lst))
(defun (setf new-cadar) (new-value lst)
(rplaca (cdar lst) new-value)
new-value)
Note how if we do (incf (my-cadar place)), there is a wasteful duplicate traversal of the list structure because cadar is called to get the old value and then cdar is called again to calculate the cell where to store the new value.
By using the more difficult and lower level define-setf-expander interface, we can have it so that the cdar calculation is shared between the access form and the store form. So that is to say (incf (my-cadar x)) will calculate (cadr x) once and store that to a temporary variable #:c. Then the update will take place by accessing (car #:c), adding 1 to it, and storing it with (rplaca #:c ...).
This looks like:
(define-setf-expander my-cadar (cell)
(let ((cell-temp (gensym))
(new-val-temp (gensym)))
(values (list cell-temp) ;; these syms
(list `(cdar ,cell)) ;; get bound to these forms
(list new-val-temp) ;; these vars receive the values of access form
;; this form stores the new value(s) into the place:
`(progn (rplaca ,cell-temp ,new-val-temp) ,new-val-temp)
;; this form retrieves the current value(s):
`(car ,cell-temp))))
Test:
[1]> (macroexpand '(incf (my-cadar x)))
(LET* ((#:G3318 (CDAR X)) (#:G3319 (+ (CAR #:G3318) 1)))
(PROGN (RPLACA #:G3318 #:G3319) #:G3319)) ;
T
#:G3318 comes from cell-temp, and #:G3319 is the new-val-temp gensym.
However, note that the above defines only the setf expansion. With the above, we can only use my-cadar as a place. If we try to call it as a function, it is missing.
Working from Mark's approach, Rainer's post on macro-function, and Amalloy's post on transparent macrolet, I came up with this:
(defmacro with-setters (&body body)
`(macrolet ((defun-mod (name args &body body)
`(,#(funcall (macro-function 'defun)
`(defun ,name ,args ,#body) nil))))
(macrolet ((defun (name args &body body)
`(progn
(defun-mod ,name ,args ,#body)
(defun-mod (setf ,name) (new-val ,#args)
(setf ,#body new-val)))))
(progn
,#body))))
To use:
Clozure Common Lisp Version 1.8-r15286M (DarwinX8664) Port: 4005 Pid: 41757
; SWANK 2012-03-06
CL-USER>
(with-setters
(defun new-car (lst)
(car lst))
(defun new-first (lst)
(first lst)))
(SETF NEW-FIRST)
CL-USER>
(defparameter *t* (list 5 4 3))
*T*
CL-USER>
(new-car *t*)
5
CL-USER>
(new-first *t*)
5
CL-USER>
(setf (new-first *t*) 3)
3
CL-USER>
(new-first *t*)
3
CL-USER>
*t*
(3 4 3)
CL-USER>
(setf (new-car *t*) 9)
9
CL-USER>
*t*
(9 4 3)
There are some variable capture issues here that should probably be attended to, before using this macro in production code.

How do I write Push and Pop in Scheme?

Right now I have
(define (push x a-list)
(set! a-list (cons a-list x)))
(define (pop a-list)
(let ((result (first a-list)))
(set! a-list (rest a-list))
result))
But I get this result:
Welcome to DrScheme, version 4.2 [3m].
Language: Module; memory limit: 256 megabytes.
> (define my-list (list 1 2 3))
> (push 4 my-list)
> my-list
(1 2 3)
> (pop my-list)
1
> my-list
(1 2 3)
What am I doing wrong? Is there a better way to write push so that the element is added at the end and pop so that the element gets deleted from the first?
This is a point about using mutation in your code: there is no need to jump to macros for that. I'll assume the stack operations for now: to get a simple value that you can pass around and mutate, all you need is a wrapper around the list and the rest of your code stays the same (well, with the minor change that makes it do stack operations properly). In PLT Scheme this is exactly what boxes are for:
(define (push x a-list)
(set-box! a-list (cons x (unbox a-list))))
(define (pop a-list)
(let ((result (first (unbox a-list))))
(set-box! a-list (rest (unbox a-list)))
result))
Note also that you can use begin0 instead of the let:
(define (pop a-list)
(begin0 (first (unbox a-list))
(set-box! a-list (rest (unbox a-list)))))
As for turning it into a queue, you can use one of the above methods, but except for the last version that Jonas wrote, the solutions are very inefficient. For example, if you do what Sev suggests:
(set-box! queue (append (unbox queue) (list x)))
then this copies the whole queue -- which means that a loop that adds items to your queue will copy it all on each addition, generating a lot of garbage for the GC (think about appending a character to the end of a string in a loop). The "unknown (google)" solution modifies the list and adds a pointer at its end, so it avoids generating garbage to collect, but it's still inefficient.
The solution that Jonas wrote is the common way to do this -- keeping a pointer to the end of the list. However, if you want to do it in PLT Scheme, you will need to use mutable pairs: mcons, mcar, mcdr, set-mcar!, set-mcdr!. The usual pairs in PLT are immutable since version 4.0 came out.
You are just setting what is bound to the lexical variable a-list. This variable doesn't exist anymore after the function exits.
cons makes a new cons cell. A cons cell consists of two parts, which are called car and cdr. A list is a series of cons cells where each car holds some value, and each cdr points to the respective next cell, the last cdr pointing to nil. When you write (cons a-list x), this creates a new cons cell with a reference to a-list in the car, and x in the cdr, which is most likely not what you want.
push and pop are normally understood as symmetric operations. When you push something onto a list (functioning as a stack), then you expect to get it back when you pop this list directly afterwards. Since a list is always referenced to at its beginning, you want to push there, by doing (cons x a-list).
IANAS (I am not a Schemer), but I think that the easiest way to get what you want is to make push a macro (using define-syntax) that expands to (set! <lst> (cons <obj> <lst>)). Otherwise, you need to pass a reference to your list to the push function. Similar holds for pop. Passing a reference can be done by wrapping into another list.
Svante is correct, using macros is the idiomatic method.
Here is a method with no macros, but on the down side you can not use normal lists as queues.
Works with R5RS at least, should work in R6RS after importing correct libraries.
(define (push x queue)
(let loop ((l (car queue)))
(if (null? (cdr l))
(set-cdr! l (list x))
(loop (cdr l)))))
(define (pop queue)
(let ((tmp (car (car queue))))
(set-car! queue (cdr (car queue)))
tmp))
(define make-queue (lambda args (list args)))
(define q (make-queue 1 2 3))
(push 4 q)
q
; ((1 2 3 4))
(pop a)
; ((2 3 4))
q
I suppose you are trying to implement a queue. This can be done in several ways, but if you want both the insert and the remove operation to be performed in constant time, O(1), you must keep a reference to the front and the back of the queue.
You can keep these references in a cons cell or as in my example, wrapped in a closure.
The terminology push and pop are usually used when dealing with stacks, so I have changed these to enqueue and dequeue in the code below.
(define (make-queue)
(let ((front '())
(back '()))
(lambda (msg . obj)
(cond ((eq? msg 'empty?) (null? front))
((eq? msg 'enqueue!)
(if (null? front)
(begin
(set! front obj)
(set! back obj))
(begin
(set-cdr! back obj)
(set! back obj))))
((eq? msg 'dequeue!)
(begin
(let ((val (car front)))
(set! front (cdr front))
val)))
((eq? msg 'queue->list) front)))))
make-queue returns a procedure which wraps the state of the queue in the variables front and back. This procedure accepts different messages which will perform the procedures of the queue data structure.
This procedure can be used like this:
> (define q (make-queue))
> (q 'empty?)
#t
> (q 'enqueue! 4)
> (q 'empty?)
#f
> (q 'enqueue! 9)
> (q 'queue->list)
(4 9)
> (q 'dequeue!)
4
> (q 'queue->list)
(9)
This is almost object oriented programming in Scheme! You can think of front and back as private members of a queue class and the messages as methods.
The calling conventions is a bit backward but it is easy to wrap the queue in a nicer API:
(define (enqueue! queue x)
(queue 'enqueue! x))
(define (dequeue! queue)
(queue 'dequeue!))
(define (empty-queue? queue)
(queue 'empty?))
(define (queue->list queue)
(queue 'queue->list))
Edit:
As Eli points out, pairs are immutable by default in PLT Scheme, which means that there is no set-car! and set-cdr!. For the code to work in PLT Scheme you must use mutable pairs instead. In standard scheme (R4RS, R5RS or R6RS) the code should work unmodified.
What you're doing there is modifying the "queue" locally only, and so the result is not available outside of the definition's scope. This is resulted because, in scheme, everything is passed by value, not by reference. And Scheme structures are immutable.
(define queue '()) ;; globally set
(define (push item)
(set! queue (append queue (list item))))
(define (pop)
(if (null? queue)
'()
(let ((pop (car queue)))
(set! queue (cdr queue))
pop)))
;; some testing
(push 1)
queue
(push 2)
queue
(push 3)
queue
(pop)
queue
(pop)
queue
(pop)
The problem relies on the matter that, in Scheme, data and manipulation of it follows the no side-effect rule
So for a true queue, we would want the mutability, which we don't have. So we must try and circumvent it.
Since everything is passed by value in scheme, as opposed to by reference, things remain local and remain unchanged, no side-effects. Therefore, I chose to create a global queue, which is a way to circumvent this, by applying our changes to the structure globally, rather than pass anything in.
In any case, if you just need 1 queue, this method will work fine, although it's memory intensive, as you're creating a new object each time you modify the structure.
For better results, we can use a macro to automate the creation of the queue's.
The push and pop macros, which operate on lists, are found in many Lispy languages: Emacs Lisp, Gauche Scheme, Common Lisp, Chicken Scheme (in the miscmacros egg), Arc, etc.
Welcome to Racket v6.1.1.
> (define-syntax pop!
(syntax-rules ()
[(pop! xs)
(begin0 (car xs) (set! xs (cdr xs)))]))
> (define-syntax push!
(syntax-rules ()
[(push! item xs)
(set! xs (cons item xs))]))
> (define xs '(3 4 5 6))
> (define ys xs)
> (pop! xs)
3
> (pop! xs)
4
> (push! 9000 xs)
> xs
'(9000 5 6)
> ys ;; Note that this is unchanged.
'(3 4 5 6)
Note that this works even though lists are immutable in Racket. An item is "popped" from the list simply by adjusting a pointer.