Reputation: 145
I'm trying to do a list of pairs as a part of a homework assignment.
I tried doing (somewhere in the middle of a function)
(setq list1 (append list1 (cons n1 n2)))
And for some reason I don't understand, this works fine with the first pair, but as I try to append the second pair, this error pops up:
*** - APPEND: A proper list must not end with 2
How can I solve this?
So, continuing on this subject, thanks to the answer given, I was able to correct my problem. But a new one came up, and I think it is related with it. So, I have this function:
(defun action(state)
(let ((list_actions '())
(limNumActions (1- (list-length state)))
(limNumSubActions 0)
(numActions 0)
(numSubActions 0))
(loop for numActions from 0 to limNumActions do
(setq limNumSubActions (1- (list-length (nth numActions state))))
(loop for numSubActions from 0 to limNumSubActions do
(setq list_actions (append list_actions
(list (cons numActions numSubActions))))
(print 'list_actions)
(print list_actions)))))
I used the print
function as a simple "debugger". It returns this:
LIST_ACTIONS
((0 . 0))
LIST_ACTIONS
((0 . 0) (0 . 1))
LIST_ACTIONS
((0 . 0) (0 . 1) (1 . 0))
LIST_ACTIONS
((0 . 0) (0 . 1) (1 . 0) (1 . 1))
NIL
And this is exactly the result I was expecting! Except for the NIL
part... Can you understand why the list list_actions
is NIL
at the end?
Upvotes: 0
Views: 2128
Reputation: 26519
The code can be expressed more succintly as follows:
(defun action (state)
(let ((list-actions '()))
(loop for i from 0 for state-i in state do
(loop for j from 0 below (length state-i) do
(setf list-actions (append list-actions (list (cons i j))))
(print 'list-actions)
(print list-actions)))
list-actions))
If only the result is needed, it can be shorter (and less costly, because it doesn't use the expensive append
function),
(defun action (state)
(loop for i from 0 for state-i in state append
(loop for j below (length state-i) collect (cons i j))))
Upvotes: 1
Reputation:
I have tried to refine your example a bit + write a version which uses a different, but, IMO more idiomatic approach to the problem:
;; Your original version, but cleaned up a bit
(defun action (state)
(loop with list-actions = nil
with lim-num-actions = (1- (list-length state))
with lim-num-sub-actions = 0
for num-actions from 0 to lim-num-actions
do (setq lim-num-sub-actions (1- (list-length (nth num-actions state))))
(loop for num-sub-actions from 0 to lim-num-sub-actions
do (push (cons num-actions num-sub-actions) list-actions)
(format t "~&~s ~s" 'list-actions list-actions))
finally (return list-actions)))
;; A more traditional approach (if you want to use iteration)
(defun action (state)
(reverse
(loop for i in state
for j from 0
collect (cons j 0))))
;; Using a nice library to do iteration
(ql:quickload "iterate")
;; Note, you could do (in-package :iterate)
;; to lose `iterate:' prefix to make it even shorter
(defun action (state)
(iterate:iter
(iterate:for i #:on state)
(iterate:for j #:from 0)
(iterate:accumulate (cons j 0) #:by #'cons)))
;; Just another way to do this, using `reduce'
(reduce #'(lambda (a b)
(declare (ignore b))
(cons (cons (1+ (caar a)) 0) a))
(cdr (mapcar #'list '(1 2 3 4 5)))
:initial-value '((0 . 0)))
(action (mapcar #'list '(1 2 3 4 5)))
Upvotes: 0
Reputation: 43743
append
takes two lists, not a list and a single element. You need to put a list around the pair before using it in append
.
Currently the pair is being taken as part of the list, which makes the list improper and causes the second append to fail since improper lists don't exactly have an end to append to.
Upvotes: 1