2012-01-21 59 views
6

我試圖拿起Lisp的作爲我的新的語言,我有工作如何有一個函數的部分工作傳遞給它的列表中的每個元素的一些問題。defun定義一個列表作爲參數

學習如何解決這個問題的目的,我想寫師的一個非常基本的形式在列表的元素之一是0不發牢騷(而是隻返回0)

(defun divtest (elements) 
    (dolist (x elements) 
    (if (zerop x) 0()) 
    (/ elements))))) 

我嘗試運行此爲:

(divtest '(20 2 5)) 

其中產量:

*** - /: (20 2 5) is not a number 

失敗的原因似乎源於這樣一個事實:在將它們傳遞給函數之前,我並沒有「提取」列表中的元素(在這種情況下,既沒有/也沒有dolist按預期工作,因爲x從不計算爲0)。 如果我是對的,有人可以告訴我如何執行這個「提取」?


注:這個問題是有關one that I've asked earlier,但我不清楚這以前的答案的一部分,實際上是允許它工作打算與這個特定的問題,我決定進一步進入基礎

回答

5

/需要爲一個或多個參數的數字,但在你的代碼,你傳遞一個列表 - 這顯然是行不通的。功能apply是您的朋友 - (apply #'foo a b (list c d e))相當於(foo a b c d e)。注意使用的功能和最終名單之間的參數apply是可選的,所以(apply #'/ '(20 2 5))相當於(/ 20 2 5)

此外,您嘗試在消除零將無法正常工作。 dolist正在評估其身體參數列表elements每個項目,但你實際上沒有做任何事情來改變elements內容(評估你似乎期望dolist的身體是不是重新分配給源元素的結果)。

功能remove-if(及其破壞性對應物,delete-if)是您正在尋找的。下面顯示瞭如何使用它(它需要大量的可選參數,爲此不需要擔心)。

(defun divtest (elements) 
    (apply #'/ (remove-if #'zerop elements))) 

另外請注意,這將無法正常運行,如果elements列表具有零作爲它的第一個元素(假設我理解函數的意思做)。所以你可能想要類似於

(defun divtest (elements) 
    (apply #'/ (first elements) (remove-if #'zerop (rest elements)))) 

查看Hyperspec的更多細節。

+2

使用REDUCE而不是APPLY –

+0

只是好奇:它的功用是什麼? – Hugh

+0

這樣你可以處理任意長列表,而不僅僅是CALL-ARGUMENT-LIMIT(一個標準的CL常量)最大長度。 Common Lisp具有一個依賴於實現的最大參數數量。這個數字必須是50或更大。這意味着一個實現只需要支持50個參數(或更多)。因此,在某些實現中,上面的函數可能會失敗,其中數字列表比調用函數/允許的參數數量更長。 –

0

嘗試(apply/elements)代替(/ elements)。我認爲(?)應該適用於Lisp的大多數方言。

+0

你需要引述'/'除非您已經分配了功能'/'的數據單元。 – Hugh

1

或者你可以把它寫這樣

(defun divtest (elements) 
    (if (member 0 elements) 
     0 
     (apply #'/ elements))) 
1
(block exit 
    (reduce #'/ '(1 2 3 0 5) 
      :key (lambda (x) 
       (if (zerop x) 
        (return-from exit 0) 
        x)))) 
相關問題