Super newbie in Lisp but at least I am trying so forgive me if the approach seems a bit strange.
I am open to learn new ideas but I will definitely need to learn whats wrong with my approach.
I have a function that builds a list using an iterative recursive approach.
(defun create-tree-iteratively(sub-list)
(if (equal (length sub-list) 1)
sub-list
(loop for i in sub-list
do(setq subtree (list i))
do(setq sub-sub-list (remove i sub-list))
do(append subtree (create-tree-iteratively sub-sub-list))
)
)
)
Input to my program is
'(1 2 3)
Expected output is
'((1 (2 3) (3 2)) (2 (1 3) (3 1)) (3 (1 2) (2 1)))
My loops (recursion) runs file. I have issues in combing the output of recursion appropriately.
Code style
It is preferable to not have closing parentheses on their own lines, the usual
convention in Lisp is to have parentheses grouped at the end, like so:
))).
Since cons-cells have only two slots, CAR and CDR, when they are used as a list they do not hold the
length of the list. So the only way to
compute the length is to traverse the whole chain of cells, which is exactly
what your function is already doing. If your list is of size N, you'll have to
compute the length N times, which makes the number of steps in your function proportional to N*N.
In a loop, a single DO can be followed by multiple expressions, you do not need
to repeat the DO keyword. Also, add spaces before opening parentheses.
SETQ is not supposed to be applied with unbound variables, like subtree or
sub-sub-list. You should first have a surrounding let where you introduce
local variables (e.g. around the loop), or use with clauses in your
loop. Or better, use the existing facilities of LOOP to avoid doing the mutation
yourself.
The return value of APPEND is important, since it 's the
results of appending the arguments (which are left unmodified). But here you do
not use the return value, which makes the whole expression useless.
Alternative
Instead of computing the length, it is sufficient to check whether the input
lists is empty, contains one elements or more (without counting). Also, you can
use collect to collect all trees as a list. I am not sure the result for a
singleton input list is correct, maybe it should be (list list).
(defun create-tree (list)
(if (null (rest list))
;; covers both empty list and list with a single element
list
;; otherwise, collect a list of trees
(loop
for i in list
;; collect all trees rooted at i, where a tree is a list (r c1 .. cn)
;; with R the root node and C1...CN each child tree. The child trees
;; are build recursively, with i removed from the list of values.
collect (list* i (create-tree (remove i list))))))
Some initial notes.
When asking a question which involves implementing an algorithm describe the algorithm: it is not easy to guess what you want based on a single example (below I have made two guesses).
I would guess you have written in Python previously, as your code shows significant signs of 'Python braindamage' (note this is a comment about Python, which I've spent years of my life on, not about your ability). In particular:
Lisp does not confuse forms which create new bindings (variables) with assignment the way Python does. You don't create a new binding in a function by setq you create it by some binding form such as let;
You don't add new things to the end of a list by append, you create a new list which has the new things added to it, and since lists are linked lists and not variable-length arrays in drag, append takes time proportional to the length of the list.
But in one respect your code ignores an important lesson of Python: all those group-closing markers don't matter to anyone reading the code, and you should not fill lines with single group closing (or opening) markers. They are just noise which makes reading code hard. In Python, in fact, they are so invisible they don't exist at all. This is one of the things Python got right.
That being said, here are three versions of what I think you want: the first implements what I'd think of as a consistent algorithm, the second implements what I think you may want, and the final one abstracts out the termination test & can do either (or anything else)).
(defun make-permuted-tree (l)
;; this builds the tree all the way down
(if (null l)
'()
(loop for e in l
collect (cons e (make-permuted-tree (remove e l))))))
(defun make-permuted-tree/strange (l)
;; this stops before the end
(if (null (rest l))
l
(loop for e in l
collect (cons e (make-permuted-tree/strange (remove e l))))))
(defun make-permuted-tree/general (l &key (base-test (lambda (b)
(null b))))
;; this stops where you want it to, which by default is at the end
(labels ((make-permuted-tree (lt)
(if (funcall base-test lt)
lt
(loop for e in lt
collect (cons e (make-permuted-tree (remove e lt)))))))
(make-permuted-tree l)))
As examples of these:
> (make-permuted-tree/strange '(1 2 3))
((1 (2 3) (3 2)) (2 (1 3) (3 1)) (3 (1 2) (2 1)))
> (make-permuted-tree '(1 2 3))
((1 (2 (3)) (3 (2))) (2 (1 (3)) (3 (1))) (3 (1 (2)) (2 (1))))
> (make-permuted-tree/general '(1 2 3))
((1 (2 (3)) (3 (2))) (2 (1 (3)) (3 (1))) (3 (1 (2)) (2 (1))))
> (make-permuted-tree/general '(1 2 3) :base-test (lambda (b)
(null (rest b))))
((1 (2 3) (3 2)) (2 (1 3) (3 1)) (3 (1 2) (2 1)))
Related
I was trying to pop an element of a list in elisp as follows,
(pop '(1 2))
but, due to my misunderstanding, that doesn't work b/c the list hasn't been internalized as a symbol. Is there an idiomatic way to do the above, or is that not a proper approach? Messing around a bit further I found I could do
(pop (progn (setq tmp '(1 2)) tmp))
but it doesn't seem right. Is there a way to make anonymous lists and modify them in place like I was trying to do?
pop is a macro
which modifies the value of its argument,
a place.
E.g.,
(defparameter *var* '(1 2 3))
(pop *var*)
==> 1
*var*
==> (2 3)
Note that what gets modified is the value of the place, not the object contained in the place.
E.g.,
(defparameter *var-1* '(1 2 3))
(defparameter *var-2* *var-1*)
(pop *var-1*)
==> 1
*var-1*
==> (2 3)
*var-2*
==> (1 2 3)
IOW, the list (1 2 3) is not modified, only the value of the variable is.
What exactly are you trying to do?
pop doesn't do what you think it does. It doesn't modify any lists. It simply rebinds the given variable with the list's cdr.
Running (macroexpand '(pop foo)) in Emacs, I get:
(car-safe (prog1 foo (setq foo (cdr foo))))
Notice the absence of any list-modification functions such as rplaca or rplacd.
The Emacs lisp manual states about the function nconc that:
Since the last argument of nconc is not itself modified, it is reasonable to use a constant list, such as '(4 5), as in the above example. For the same reason, the last argument need not be a list
And indeed I can write
(setq x '(1 2 3))
=> (1 2 3)
(nconc x 0)
=> (1 2 3 . 0)
but that yields a totally broken list:
(length x)
=> eval: Wrong type argument: listp, 0
(butlast x)
=> butlast: Wrong type argument: listp, 0
How can I retrieve the original list? (reverse (cdr (reverse '(1 2 3 . 0)))) doesn't cut it either.
In which contexts is this a useful pattern? In the standard distribution some functions in minibuffer.el use it, in particular completion-all-completions and the like.
They're not "broken" lists; they're actually known as improper lists (as opposed to nil-terminated lists, which are proper lists). Many list functions, such as length and butlast that you just named, expect proper lists, and listp returns true only for proper lists.
Improper lists are used in association lists (where the associations are often not proper; though the alist itself must be proper).
If you want to make an improper list proper, you have two options:
Remove the "improper" element.
Treat the improper element as the last element of the proper list.
Here's a procedure I wrote called properise which will do the former:
(defun properise (x)
(let ((r nil))
(while (consp x)
(push (pop x) r))
(nreverse r)))
(If you want the latter behaviour, add (unless (null x) (push x r)) just before the nreverse line.)
Generally I would avoid creating data structures like that, where the last element is a cons cell with some object other than NIL in the cdr... It makes debugging harder, it's a hack, makes code more difficult to understand, ...
I'm still unsure why this is a good pattern, but here's an easy way of getting a proper list out of an improper one, without making a copy:
(defun nmake-proper-list (x)
(let ((y (last x)))
(setcdr y nil)
x))
We just covered loops today in class and I've got a few things I need to do. Put simply, I have to build a list using loops instead of recursion. I seem to be at a stumbling block here. For this example, we need to do a simple countdown. The function takes an argument and then returns a list of all the positive integers less than or equal to the initial argument. (countdown 5) => (5 4 3 2 1)
I'm having a hard time getting loops for whatever reason. The ones we talked about was Loop, Do, Dotimes, and Dolist. I've tried this with a couple loops and always end up with a similar result.
(defun countdown (num)
(cond ((= num 0) nil)
(T (let* ((list nil))
(loop
(if (= num 0) (return list)
(setf list (cons list num)))
(setf num (- num 1)))))))
My output shows up like this:
(((((NIL . 5) . 4) . 3) . 2) .1)
update: I've solved the issue. Apparently I needed to reverse the order in the cons, so num comes before list. Does anyone care to explain this? I thought you put the list first and then what you put second would be added to the end of it. At least, that's how I've been using it so far without issue.
Reverse the arguments to cons (and why)
You wrote in an answer (that, since it asks for more information, perhaps should have been a comment):
I've solved the issue. Apparently I needed to reverse the order in the
cons, so num comes before list. Does anyone care to explain this? I
thought you put the list first and then what you put second would be
added to the end of it. At least, that's how I've been using it so far
without issue.
The function is documented in the HyperSpec clearly: Function CONS. The examples in the documentation show, e.g.,
(cons 1 (cons 2 (cons 3 (cons 4 nil)))) => (1 2 3 4)
(cons 'a (cons 'b (cons 'c '()))) => (A B C)
(cons 'a '(b c d)) => (A B C D)
and even the note
If object-2 is a list, cons can be thought of as producing a new list which is like it but has object-1 prepended.
It may help to read through 14.1.2 Conses as Lists, as well, which includes:
A list is a chain of conses in which the car of each cons is an element of the list, and the cdr of each cons is either the next link in the chain or a terminating atom.
Concerning loop
Many of the answers here are pointing out to you that the loop form includes a special iteration language. That's true, but it can also be used in the way that you're using it. That way is called a simple loop:
6.1.1.1.1 Simple Loop
A simple loop form is one that has a body containing only compound
forms. Each form is evaluated in turn from left to right. When the
last form has been evaluated, then the first form is evaluated again,
and so on, in a never-ending cycle. A simple loop form establishes an
implicit block named nil. The execution of a simple loop can be
terminated by explicitly transfering control to the implicit block
(using return or return-from) or to some exit point outside of the
block (e.g., using throw, go, or return-from).
Simple loops probably aren't as common as loops using the nicer features that loop provides, but if you just covered this in class, you might not be there yet. The other answers do provide some good examples, though.
If you speaking about common lisp loop, your countdown may look like this:
(defun countdown (from-number)
(loop :for x :from from-number :downto 1 :collect x))
CL-USER> (countdown 10)
(10 9 8 7 6 5 4 3 2 1)
Using loop, which has its own "special-purpose language" that does not really look like Lisp:
(defun countdown (n)
(loop
for i from n downto 1
collect i))
Or using do:
(defun countdown (n)
(do ((i 1 (1+ i))
(res nil (cons i res)))
((> i n) res)))
See here, especially chapters 7 and 22.
I'm new to Lisp and I'm having trouble figuring out how I add a list to another list. I start with an empty list, and I have to add new lists, each containing three elements. For example,
(add '(1 2 3) '())
would return ((1 2 3)) [let's call it new-list], and adding a new list to this new one, for example
(add '(4 5 6) new-list)
would return ((1 2 3) (4 5 6)) or ((4 5 6) (1 2 3))
I've tried a few different ways, but so far the closest I've come up was ((((1 2 3)) (4 5 6)) (7 8 9))
I was using something like this:
(defun add (lst new-let)
(if (null lst) '()
(setf new-lst (cons new-lst (cons lst '()))))
Have you tried :
(defun add (thing lst) (append lst (list thing)))
I haven't tried this with Common Lisp as I am more of a Scheme kind of guy, bu I think it would work.
The way I read it, your requirement is exactly cons (non destructive) or push (destructive).
You being new to LISP I'd like to give you an alternative to the accepted answer.
Lists are singly linked list chains. Such structure allows for adding and removing in front to be a constant time operation while adding or removing something from the end would take as many turns as there are elements in the list in both time and space (it will have to recreate the list structure on it's way).
(defun add (element list)
(cons element list))
This looks very familiar.. It's actually just a wrapper to cons. So lets imagine you have a practical application where you'd like to use add, but needed the elements in the order in your question. One way to do it would then be to finish up first (add whats to add), then do one reverse or nreverse (if every element was made in your function and mutation won't matter for the outside)..
(defun fetch-all (num-elements thunk &optional acc)
(if (zerop num-elements)
(nreverse acc)
(fetch-all (- num-elements 1) thunk (add (funcall thunk) acc)))); add == cons
Okay I want to count the number of times each [number] has appeared inside a list using Scheme.
How can I do that ? I also would like to store the counter of the given number and re-construct a new list.
For example I have the following list ((1 2)(2 5)(5 7)(7 8)(6 8)(4 6)(3 4)(1 3)(4 8))
I was thinking first flatten the list, and then set a counter for each number (don't know how to do it). And then reconstruct a new list corresponding to the original number. (this can be tricky ? I need to store a temporary variable ?)
Say from this example the number 1 appeared twice, number 2 appeared twice, number 3 twice etc... so I would like to recreate a new list to something like this:
(1 2) (2 2) (3 2) (4 3) (5 2) (7 2) (6 2) (8 3)
any idea how I can achieve this ?
Update:
I was thinking to implement an increment counter helper something like this ?
(define inc-counter
(let ((counter 0))
(lambda () (set! counter (+ counter 1)))))
A good answer mostly depends on your implementation (modulo R6RS). In the case of PLT scheme, here's a quick definition that does that. It avoids flattening the list -- you only need to scan each item, so there's no point in constructing a new copy when scanning a tree is so simple. Also, this function sorts the resulting list (since it will be all scrambled on its way out of the hash table). Even if you're using some completely different implementation, it should be easy to translate:
(define (counts x)
(define t (make-hash))
(define (scan x)
(if (list? x)
(for-each scan x)
(hash-set! t x (add1 (hash-ref t x 0)))))
(scan x)
(sort (hash-map t list) < #:key car))
(Note, BTW, that if this is any kind of HW question, then this code is much too practical to be useful as an answer...)
Use an accumulator parameter to flatten which keeps an association list of how many times each has appeared. That way you'll have all the data you need each time around the loop.
For example, you might write factorial like this:
(define (factorial num accum)
(if (= num 0) accum (factorial (- num 1) (* accum num)))
And call it with (factorial 10 1). At the end, the value of the accumulator is the result of the function. In your example, you'd write a little helper function that would call flatten and keep track of the number of times each number has appeared.
Perhaps not the most efficient solution, but I think you could achieve this by partitioning the list by its first element until there are no more elements in the list. The list of in-elements would then be all of the numbers in the list that were the same as the first number. This process could be repeated on the list of out-elements until there were no more elements in the list.
You could use a hashtable mapping the number to its number of occurrences. Create it with (make-hash).