2016-03-13 39 views
0

我試圖通過向一個空列表,使用下面的代碼在LISP構建元素的唯一列表: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)) 
     ) 
    ) 

這個特殊的代碼導致NIL當我打電話(makeset「(abbacdba)) - 它應該導致(abcd),而不考慮順序) - 但是在我看來,它應該從SET1中添加一個原子,這個原子在每次迭代中還不在UNIQ中。你可以不添加到do循環中聲明的空列表,還是有一些其他問題我有?順便說一下,我正在使用clisp。

+1

請修正標題是一個道理。這可能涉及到首先發現真實的事實(通過剝去一切無關緊要的東西)。 – user2864740

+1

除了以前的評論,請修復代碼格式:縮寫,縮進,掛件。 Emacs應該有所幫助。 – sds

+1

簡短的回答是'(cons x y)'不會修改*任何東西;它*返回*一個新的細胞。之後'x'和'y'與之前的一樣。結果是你想要的新價值。這意味着你需要像'(setq y(cons x y))'這樣的東西。 –

回答

5

1.使用正確的格式

詢問一些關於共Lisp語言時,請使用正確的格式。 例如,請參閱Google搜索"common lisp formatting conventions"返回的前三頁。

這裏是應用到您的功能的常規格式的一個例子:當可能

兩者的功能都在共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)) 
      (push (car set1) uniq))) 
    (setf set1 (cdr set1)))) 

2.使用原語功能。

remove-duplicates返回一個沒有重複元素的列表,member檢查一個元素是否屬於一個集合。

3.錯誤在你的函數

如果你仍然想使用你的函數,而不是remove-duplicates,這裏是它的問題。

如果你想修改一個列表,你應該使用一個修改某些東西的函數。 cons功能建立一個新的對,但確實不會修改任何東西。因此,在您的形式(cons (car set1) uniq)你在這個意義上添加新的元素uniq你獲得新的列表(car set1)作爲第一要素,並作爲列表的其餘部分unique的元素,但是這個新的列表被立即丟棄,因爲它不是分配給任何東西。

您可以通過使用宏setf以這種方式分配的新值局部變量uniq要麼改變這樣的:

(setf uniq (cons (car set1) uniq)) 

,或者你可以寫的等價形式,通過使用宏push的:

(push (car set1) uniq) 

最後,請注意您的cond功能makeset裏面可以用更簡潔when,resul更換婷在這個函數:

(defun makeset (set1) 
    (do ((uniq nil)) 
     ((null set1) uniq) 
    (when (not (memset (car set1) uniq)) 
     (push (car set1) uniq)) 
    (setf set1 (cdr set1)))) 
+1

也''除去'或用'替換''做'(let ...(dolist(x set1)...))' – 6502

+0

非常感謝。我會研究如何格式化我的代碼,使其更具可讀性。我很欣賞你寫的示例代碼。這是我在LISP中編寫的第一批程序之一,所以我仍然有很多東西需要學習。 –

1

所有的更新可以在DO步進的形式來完成。無需PUSHSETF

(defun makeset (set1) 
    (do ((uniq nil (if (memset (car set2) uniq) 
         uniq 
        (cons (car set2) uniq))) 
     (set2 set1 (cdr set2))) 
     ((null set2) uniq))) 
相關問題