Reputation: 3
I'm trying to construct a unique list of elements by adding to an empty list, using the following code in LISP:
;;;MEMSET - return T if an atom is a top-level member of a set, else NIL
;;;This is needed for the makeset function
(DEFUN MEMSET (ATM L)
(COND ( ( NULL L) NIL )
( (EQL ATM(CAR L)) T )
( T (MEMSET ATM (CDR L)) )
)
)
(DEFUN MAKESET(SET1)
(DO ((UNIQ ()))
( (NULL SET1) UNIQ)
(COND ( (NOT (MEMSET (CAR SET1) UNIQ))
(CONS (CAR SET1) UNIQ)
)
)
(SETF SET1 (CDR SET1))
)
)
This particular code results in NIL when I call (makeset '(a b b a c d b a)) - it should result in (a b c d), with no regard to order) - but it looks to me like it should be adding one atom from SET1 that isn't yet in UNIQ each iteration. Can you not add to an empty list declared in a do loop, or is there some other issue I'm having? By the way, I'm using clisp.
Upvotes: 0
Views: 1205
Reputation: 139251
All the updates can be done with the stepping forms in DO
. No need for PUSH
or SETF
:
(defun makeset (set1)
(do ((uniq nil (if (memset (car set2) uniq)
uniq
(cons (car set2) uniq)))
(set2 set1 (cdr set2)))
((null set2) uniq)))
Upvotes: 1
Reputation: 27404
1. Use proper formatting
Please use a proper formatting when asking something about Common-Lisp. See for instance the first three pages returned by googling "common lisp formatting conventions".
Here is an example of conventional format applied to your functions:
;;; Memset - return T if an atom is a top-level member of a set, else NIL
;;; This is needed for the makeset function
(defun memset (atm l)
(cond ((null l) nil)
((eql atm (car l)) t)
(t (memset atm (cdr l)))))
(defun makeset (set1)
(do ((uniq ()))
((null set1) uniq)
(cond ((not (memset (car set1) uniq))
(push (car set1) uniq)))
(setf set1 (cdr set1))))
2. Use primitive functions when possible
Both your functions are primitive in Common-Lisp.
remove-duplicates
returns a list without duplicate elements, member
checks if an element belong to a set.
3. The error in your function
If you still want to use your function, instead of remove-duplicates
, here is the problem in it.
If you want to modify a list, you should use a function that modifies something. The cons
functions builds a new pair but does not modify anything. So in your form (cons (car set1) uniq)
you add a new element to uniq
in the sense that you obtain a new list with (car set1)
as first element and the elements of unique
as rest of the list, but this new list is immediately discarded because it is not assigned to anything.
You can change this either by using the macro setf
to assign the new value to the local variable uniq
in this way:
(setf uniq (cons (car set1) uniq))
or you can write the equivalent form, through the use of the macro push
:
(push (car set1) uniq)
Finally, note that your cond
inside the makeset
function can be replaced by the more terse when
, resulting in this function:
(defun makeset (set1)
(do ((uniq nil))
((null set1) uniq)
(when (not (memset (car set1) uniq))
(push (car set1) uniq))
(setf set1 (cdr set1))))
Upvotes: 5