2015-02-17 44 views
2

關於功能nconc該Emacs lisp manual狀態:建立一個非列表尾的列表有什麼意義?

由於nconc的最後一個參數是本身不改性,它是合理的使用恆定列表,如「(4 5),如在上面的例子。出於同樣的原因,最後一個參數不一定是列表

而事實上我可以寫

(setq x '(1 2 3)) 
=> (1 2 3) 

(nconc x 0) 
=> (1 2 3 . 0) 

但產生一個完全破碎列表:

(length x) 
=> eval: Wrong type argument: listp, 0 

(butlast x) 
=> butlast: Wrong type argument: listp, 0 
  • 哪有我檢索原始列表? (reverse (cdr (reverse '(1 2 3 . 0))))也不會削減它。
  • 在哪些情況下這是一種有用的模式?在標準分配中,minibuffer.el中的一些功能使用它,特別是completion-all-completions等。
+1

BTW,使用文字數據,如''(1 2 3)',作爲'nconc'的非最後一個參數在技術上沒有問題。文字基準應該被認爲是不變的。 – 2015-02-18 06:26:31

回答

5

他們不是「破碎」名單;他們實際上被稱爲不正確的列表(而不是nil-終止列表,它們是正確的列表)。許多列表函數(例如您剛剛命名的lengthbutlast)都需要正確的列表,並且listp僅適用於正確的列表。

在關聯列表中使用不正確的列表(其中關聯通常不合適;儘管alist本身必須正確)。


如果你想使一個不正確的列表正確,你有兩個選擇:

  • 刪除了「不恰當」的元素。
  • 將不正確的元素視爲正確列表的最後一個元素。

這裏有一個程序我編寫的名爲properise這將做前:

(defun properise (x) 
    (let ((r nil)) 
    (while (consp x) 
     (push (pop x) r)) 
    (nreverse r))) 

(如果你想後者的行爲,只是nreverse行前加(unless (null x) (push x r))

+0

謝謝你的回答!對於不正確的列表,有沒有簡單的等價於'butlast'? – 2015-02-18 01:00:17

+0

沒有,但我編輯帖子添加一個'properise'程序,這將把你的不適當的列表變成一個正確的列表。然後你可以調用'butlast'。 – 2015-02-18 01:36:18

+0

謝謝。這是一個非常棘手的過程。我想知道爲什麼'completion-all-completions'這樣返回結果。 – 2015-02-18 02:22:19

2

一般來說,我會避免創建類似的數據結構,其中最後一個元素是在cdr中使用除NIL之外的對象的cons單元格...它使調試更加困難,這是一種黑客攻擊,使代碼更難理解,...

+0

我同意,OP也一樣。事實上,OP正試圖弄清楚爲什麼Emacs中的completion-all-completions(有時候)會返回不正確的列表。 – 2015-02-18 05:35:56

+1

@ ChrisJester-Young:對,並且很難弄清楚,更加顯示應該避免像那樣的「聰明」的東西。其實我不能直接記得任何使用類似這樣的Lisp軟件...... – 2015-02-18 05:58:41

+0

我完全同意。許多口齒有這些類型的陷阱。在某些情況下,'(setq x '(1 2 3))可能會導致問題,因爲它不是一個*適當的*列表,您應該這樣做(setq x (list 1 2 3)),而不是 – 2015-02-18 07:59:21

0

我仍然不能確定爲什麼這是一個很好的模式,但這裏得到一個合適的列表進行不正當的一個的一個簡單的方法,不進行復制:

(defun nmake-proper-list (x) 
    (let ((y (last x))) 
    (setcdr y nil) 
    x))