以列表作为参数进行defun

时间:2012-01-21 03:04:42

标签: lisp common-lisp

我正在尝试将Lisp作为我的新语言,并且我遇到了一些问题,如何让一部分函数在传递给它的列表的每个元素上运行。

为了学习如何解决这个问题,我试图写一个相当基本的除法形式,当列表中的一个元素为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有关,但由于我不清楚上一个答案的哪一部分实际上允许它按照预期的具体问题工作,我决定进一步研究基本

4 个答案:

答案 0 :(得分: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的结果正如您所期望的那样,s body不会重新分配给source元素。

函数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。

答案 1 :(得分:1)

或者你可以这样写

(defun divtest (elements)
  (if (member 0 elements)
      0
      (apply #'/ elements)))

答案 2 :(得分:1)

(block exit
  (reduce #'/ '(1 2 3 0 5)
          :key (lambda (x)
                 (if (zerop x)
                     (return-from exit 0)
                   x))))

答案 3 :(得分:0)

尝试(apply / elements)代替(/ elements)。我认为(?)应该适用于大多数Lisp方言。