Parens 'options' with the cond operator? - common-lisp

I decided I would tidy up the following function. The idea being that it uses cond but it also contains ifs, which makes it hard to cognitively process. This is bst code from the book ansi common lisp.
(defun percolate (bst)
(cond ((null (node-l bst))
(if (null (node-r bst))
nil
(rperc bst)))
((null (node-r bst)) (lperc bst))
(t (if (zerop (random 2))
(lperc bst)
(rperc bst)))))
My idea was to remove the ifs, by adding more cases in the cond, then justify the whole thing nicely with cause on the left, effect on the right.
Here's what I came up with:
(defun percolate (bst) ; [6,7,7a]
(cond (((and (null (node-l bst)) (null (node-r bst))) nil)
((null (node-l bst)) (rperc bst))
((null (node-r bst)) (lperc bst))
(t (if (zerop (random 2))
(lperc bst)
(rperc bst))))))
However, this produces the error
*** - SYSTEM::%EXPAND-FORM: (AND (NULL (NODE-L BST)) (NULL (NODE-R BST))) should be a
lambda expression
I can find other posts about this problem on stack overflow, like here but I still don't understand it. Is cond a departure from normal lisp syntax somehow? I'd like to identify the assumption I'm making which is wrong.
For the record, the below code is accepted by the interpreter, but obviously we don't want to write it like that.
(defun percolate (bst) ; [6,7,7a]
(let ((both-null (and (null (node-l bst)) (null (node-r bst))))
(l-null (null (node-l bst)))
(r-null (null (node-r bst))))
(cond ((both-null nil)
(l-null (rperc bst))
(r-null (lperc bst))
(t (if (zerop (random 2))
(lperc bst)
(rperc bst)))))))

cond syntax:
cond {clause}*
clause::= (test-form form*)
examples
(cond (var)
(var a b c)
(var (f a) (f b) (f c))
((and var-a var-b) (f c) (f d))
((f a) b (f c) d)
(t (f a) (f b) (f c)))
Means:
zero or more clauses.
each clause is inside a list and begins with a test form and then zero or more forms
let syntax:
let ({var | (var [init-form])}*)
declaration*
form*
Means:
zero or more variable clauses inside one list
each variable clause is either a variable or a list of variable and optional init-form
the variable clauses list is followed by optional zero or more declarations and then zero or more body forms
Example:
(let ()
)
(let (a)
a)
(let (a
(b t))
(and a b))
(let ((a t)
(b (not t)))
(or a b))

I identified a possible answer during the course of writing the post.
I'll still make the post though as it would be great to receive any further clarification and discussion.
Lets first state what we know. With let, it is necessary to have a surrounding pair of parens to contain all of the individual lexical variables assigned:
(let ((both-null (and (null (node-l bst)) (null (node-r bst))))
(l-null (null (node-l bst)))
(r-null (null (node-r bst))))
But it turns out a mistake to assume cond follows the same pattern (which I had assumed).
Cond works just fine without surrounding parens.
The following form is accepted by the interpreter:
(defun percolate (bst) ; [6,7,7a]
(cond ((and (null (node-l bst)) (null (node-r bst))) nil)
((null (node-l bst)) (rperc bst))
((null (node-r bst)) (lperc bst))
(t (if (zerop (random 2))
(lperc bst)
(rperc bst)))))
However (here's the part that bit me), it turns out the interpreter will accept extra parens, if one unwittingly copies the let form syntax.
... unless! - the first form in one of the cond expressions is itself is a compound form, i.e. not an atom.
I'd greatly appreciate any additional answers from the community which can explain further and/or extend or correct what I've found here.
UPDATE: my test of validity of these forms had been to paste them into the REPL. It turns out that is not sufficient, you must compile, as explained in the comments by Rainer Joswig.
So, some conclusions
Make sure to remember cond does not follow the syntactic model of let
Be careful because if you fall into that assumption, you can get away with it for a while then suddenly it wont work for the reason given above.
If you've been writing cond with extra parens, practice it correctly and learn to recognise it without.

Related

Defining a type on a list that begins with a particular symbol

I am trying to use generic functions' ability to specify behaviour based on the first argument of a list.
In other words, I want the list (atypelist 1 2 3) and the list (btypelist 1 2 3) to have their individual behaviour when passed to foo. So far, this is what I came up with:
(deftype atypelist (lst)
`(eq (car ,lst) 'atypelist))
(deftype btypelist (lst)
`(eq (car ,lst) 'btypelist))
(defmethod foo ((lst atypelist))
(format nil "success atypelist: ~S" lst))
(defmethod foo ((lst btypelist))
(format nil "success btypelist: ~S" lst))
However, when I call (typep (list 'atypelist 1 2 3) 'atypelist) I get the following error:
error while parsing arguments to DEFTYPE ATYPELIST:
too few elements in
()
to satisfy lambda list
(LST):
exactly 1 expected, but got 0
I am guessing the error is in my definition of atypelist.
Questions:
Is there a better way to get the functionality I am looking for?
If yes - what is the way?
If not - how to properly define a type on a list/cons that has a particular symbol in the car?
Before I start: what you want to do can't work, and is confused in two ways.
Firstly deftype defines a type in terms of other type specifiers: the body of a deftype form must expand into a type specifier, not an expression, as yours does. And deftype's arguments are not the thing you want to check the type for, they are parts of the type specification.
In this case you want to specify that the thing is a cons, and that its car is eql to something. Fortunately there are specializing type specifiers for both of these things, and you end up with something like this:
(deftype cons-with-specified-car (x)
`(cons (eql ,x) t))
And now
> (typep '(1) '(cons-with-specified-car 1))
t
> (typep '(a) '(cons-with-specified-car a))
t
> (typep '() '(cons-with-specified-car a))
nil
And if you want:
(deftype cons-with-a ()
'(cons-with-specified-car a))
and now
> (typep '(a) 'cons-with-a)
t
Secondly none of this will work because this it not how CLOS works. CLOS dispatches on classes not types, and you have merely defined a type, not a class: your method definitions simply cannot work, since classes cannot be parametrized in this way like types can.
Some ways you might achieve what you want.
If what you want to do is to dispatch on the first element of a list, then the obvious approach, if you want to use CLOS, is to use a two-level approach where you first dispatch on the class of the thing (cons is a class), and then use eql specializers to pick out the things you want.
(defgeneric select (it)
(:method ((it cons))
(select* (car it) it))
(:method (it)
nil))
(defgeneric select* (key it)
(:method (key it)
(format t "~&unknown key ~S in ~S~%" key it)))
(defmethod select* ((key (eql 'a)) it)
(format t "~&~S begins with a~%" it))
However in a case like this, unless you very much want the extensibility that CLOS gets you (which is a good reason to use CLOS here), I'd just use typecase. You could do this using the type defined above:
(defun select (it)
(typecase it
((cons-with-specified-car a)
'(cons a))
(cons
'cons)
(t
nil)))
or, probably simpler, just use what the deftype expands into:
(defun select (it)
(typecase it
((cons (eql a) t)
'(cons a))
(cons
'cons)
(t
nil)))
Finally probably what anyone doing this would actually write (again, assuming you do not want the extensibility CLOS gets you) is:
(defun select (it)
(typecase it
(cons
(case (car it)
...))
(t
...)))
Here is a possible solution, using the type specifier satisfies:
CL-USER> (defun is-atypelist (list)
(eq (car list) 'atypelist))
IS-ATYPELIST
CL-USER> (defun is-btypelist (list)
(eq (car list) 'btypelist))
IS-BTYPELIST
CL-USER> (deftype atypelist ()
`(satisfies is-atypelist))
ATYPELIST
CL-USER> (deftype btypelist ()
`(satisfies is-btypelist))
BTYPELIST
CL-USER> (typep (list 'atypelist 1 2 3) 'atypelist)
T
CL-USER> (typep (list 'atypelist 1 2 3) 'btypelist)
NIL
Note that this does not define a class, but a type, if this is what you need.
Is there a better way to get the functionality I am looking for?
1. Wrap your lists in container types
(defclass lst () ((items :initarg :items :reader items)))
(defclass alst (lst) ())
(defclass blst (lst) ())
It may be a little bit more cumbersome to work with but this is pretty much straightforward and not too suprising.
2. Douple-dispatch
(defgeneric foo (val))
(defgeneric foo/tag (tag val))
For example:
(defmethod foo ((c cons))
(destructuring-bind (tag . list) c
(foo/tag tag list)))
3. Define a custom method combination
It should be possible to hack the meta-object protocol dispatch mechanism to dispatch on the first item of a list. I wouldn't recommend it however.
4. Use a different dispatch mechanism
Use a completely different dispatching mechanism outside of CLOS, like pprint-dispatch does. For example you may want to use trivia or optima pattern-matching libraries, or cl-algebraic-data-type. This may be more useful if you are dealing with trees of symbols.

Representing a queue as a procedure with local state

Section §2.1.3 at page 90 explains, with a very clear example, that first class functions in a language make functions themselves and data be the same thing looked at from different perspectives, or, to cite the book:
the ability to manipulate procedures as objects automatically provides the ability to represent compound data.
At page 266, exercise 3.22 from Section §3.3.2, proposes the following
Instead of representing a queue as a pair of pointers, we can build a queue as a procedure with local state. The local state will consist of pointers to the beginning and the end of an ordinary list. Thus, the make-queue procedure will have the form
(define (make-queue)
(let ((front-ptr ...)
(rear-ptr ...))
<definitions of internal procedures>
(define (dispatch m) ...)
dispatch))
Complete the definition of make-queue and provide implementations of the queue operations using this representation.
I easily came up with the following (I've used names the-list and last-pair instead of front-ptr and rear-ptr because I found it clearer, in this case):
(define (make-queue)
(let ((the-list '())
(last-pair '()))
(define (dispatch m)
(cond ((eq? m 'empty) (null? the-list))
((eq? m 'front) (if (null? the-list)
(error "can't take front of empty list")
(car the-list)))
((eq? m 'ins) (lambda (e)
(if (null? the-list)
(begin (set! the-list (list e))
(set! last-pair the-list))
(begin (set-cdr! last-pair (list e))
(set! last-pair (cdr last-pair))))
the-list))
((eq? m 'del) (begin
(if (null? the-list)
(error "can't delete from emtpy list")
(set! the-list (if (pair? the-list) (cdr the-list) '())))
the-list))
((eq? m 'disp) (display the-list)) ; added this for convenience
(else "error")))
dispatch))
(define (empty-queue? q) (q 'empty))
(define (front-queue q) (q 'front))
(define (insert-queue! q e) ((q 'ins) e))
(define (delete-queue! q) (q 'del))
(define (display-queue q) (q 'disp))
which seems to work pretty fairly well…
… except for one crucial point!
At the beginning of §3.3.2 the two desired mutators (that are part of the queue interface) are defined like this (my emphasis):
(insert-queue! <queue> <item>)
inserts the item at the rear of the queue and returns the modified queue as its value.
(delete-queue! <queue>)
removes the item at the front of the queue and returns the modified queue as its value, signaling an error if the queue is empty before the deletion.
My solution doesn't abide by those parts of the definition, because both insert-queue! and delete-queue! are returning the-list, which is the bare list, an implementation detail of the queue interface. Indeed, my solution doesn't support things like these
(define q (make-queue)) ; ok
(insert-queue! (insert-queue! q 3) 4) ; doesn't work
(delete-queue! (delete-queue! q)) ; doesn't work
whereas I think it should.
I guess that the solution should see delete-queue! and insert-queue! return a mutated version of the dispatch function.
How do I do that?
No need for that. Simply define
(define (insert-queue! q e)
((q 'ins) e)
q)
(define (delete-queue! q)
(q 'del)
q)
The design is not clean though, as in, these queues are not persistent. The new version and the old share the same underlying buffer (list). There is no old version preserved anymore, just the current version.
So we don't return a new, modified queue; we return the same queue which has been mutated. Conceptually, that is. On a little bit lower level, we return the same dispatch procedure which is a part of the same closure which holds the same internal binding for the internal buffer, which has been mutated.
By the way, using the head sentinel trick, were you start with e.g. (list 1) instead of '(), usually leads to much simplified, clearer code.

Concatenate List of Characters Recursively in Common LISP

So I'm attempting to implement a Caesar cipher in LISP recursively, and I've got the basic functionality working. The problem is it returns a list of characters, and calling concatenate 'string on the return statement just returns the same list of characters plus a "". What am I doing wrong here?
(defun caesar (s n)
(if (null (concatenate 'list s))
'()
(cons
(code-char (+ n (char-code (car (concatenate 'list s)))))
(caesar (coerce (cdr (concatenate 'list s)) 'string) n)
)
)
)
The right approach to something like this is to do the conversion between string & list in a wrapper of some kind & then have the main function work on the list.
Here is an approach to doing that which uses some of the power and elegance of CL. This:
uses CLOS methods to do wrapping -- this will presumably make it ineligible for submission as homework, in case that is what it is, but is a good demonstration of how pretty CLOS can be I think, and is also how I would actually write something like this;
uses coerce in the wrapper method rather than concatenate to change types, since that's what it's for;
intentionally does not deal with some of the other problems of the original code around recursion & char-codes.
First of all here is a version which uses two methods: a wrapper method (defined in the generic function definition for convenience) and then the recursive method which does the work:
(defgeneric caesar (text n)
(:method ((text string) n)
;; if we're given a string just turn it into a list, then recurse
;; on the list & turn it back to a string (of the same type, hence
;; TYPE-OF).
(coerce (caesar (coerce text 'list) n) (type-of text))))
(defmethod caesar ((text list) n)
;; The recursive level (note this has various issues which are in
;; the original code & not addressed here
(if (null text)
'()
(cons (code-char (+ n (char-code (first text))))
(caesar (rest text) n))))
Secondly here is a slightly too-clever approach, using a special termination-on-null method. I would not recommend this, but it's a neat demonstration of the kind of thing CLOS can do.
(defgeneric caesar (text n)
(:method ((text string) n)
;; if we're given a string just turn it into a list, then recurse
;; on the list & turn it back to a string (of the same type, hence
;; TYPE-OF).
(coerce (caesar (coerce text 'list) n) (type-of text))))
(defmethod caesar ((text null) n)
;; termination
'())
(defmethod caesar ((text list) n)
;; The recursive level (note this has various issues which are in
;; the original code & not addressed here
(cons (code-char (+ n (char-code (first text))))
(caesar (rest text) n)))
I would be tempted to combine with-output-to-string and labels (for the recursive bit):
(defun caesar (s n)
(with-output-to-string (cipher)
(labels ((beef (s)
(when s
(princ <whatever> cipher)
(beef (rest s)))))
(beef (coerce s 'list)))))
Caveat: the above is thoroughly untested and simply typed into this message, so likely will not even compile. It just makes the suggestions more cncrete.

What does this self referencing code do?

What is this self reference for?
Could it be written in any other way?
Is there any advantage?
(defmacro sublet (bindings% &rest body)
(let ((bindings (let-binding-transform
bindings%)))
(setq bindings
(mapcar
(lambda (x)
(cons (gensym (symbol-name (car x))) x))
bindings))
`(let (,#(mapcar #'list
(mapcar #'car bindings)
(mapcar #'caddr bindings)))
,#(tree-leaves
body
#1=(member x bindings :key #'cadr)
(caar #1#)))))
It's just a way of reusing structure somewhere else. In the macro you have:
(tree-leaves body
#1=(member x bindings :key #'cadr)
(caar #1#))
Which is just a fancy way of writing:
(tree-leaves body
(member x bindings :key #'cadr)
(caar (member x bindings :key #'cadr)))
On the positive side if you correct a bug in the member form you'll fix it both places, but it's runs the same code twice so if member was expensive this wouldn't be the wise way to do it. However it is a macro, thus run at compile time, and member is fairly fast on mall lists (small == millions of elements or below) so I guess it won't matter if you read the references just as good as any other CL code. An alternative and perhaps more readable for other kind of lispers would be:
(let ((found (member x bindings :key #'cadr)))
(tree-leaves body found (caar found)))

Recursion in Scheme with Booleans

How would you write a base case for a recursive function that is also a boolean? The problem comes up in the project Scoring Poker Hands in Simply Scheme (http://www.eecs.berkeley.edu/~bh/ssch15/poker.html).
The only thing I can think of is putting #t when the list has reached the count of 1 or less, but then the function only returns #t because all lists would be reduced to one element in it.
Typically it depends on what the function is supposed to do. For instance, an every? function that check whether every element of a list satisfies some predicate should return #t in the base case, because it is true that every element in an empty list satisfies the predicate. On the other hand, a some? function should return #f, since it is false that some element in an empty list satisfies the predicate.
(define (some? predicate list)
(if (null? list)
#f
(if (predicate (car list))
#t
(some? predicate (cdr list)))))
Of course, with functions returning a boolean like this, you can often encode the logic more directly by using and, or, and not:
(define (some? predicate list)
(and (not (null? list))
(or (predicate (car list))
(some? predicate (cdr list)))))
The every? case would be:
(define (every? predicate list)
(if (null? list)
#t
(if (not (predicate (car list)))
#f
(every? predicate (cdr list)))))
and the more direct version of every? (using boolean operators rather than if, #t, and #f):
(define (every? predicate list)
(or (null? list)
(and (predicate (car list))
(every? predicate (cdr list)))))

Resources