2

我的代码输出有问题,我认为是在检查列表是否为空的条件时。

我要完成的问题是:编写一个函数vecmul,将两个简单的数字列表作为输入。vecmul 应该将这些列表按坐标相乘,就像向量相乘一样。假设这两个列表的长度相同。[例如,(vecmul '(2 3 4 5) '(1 4 5 2))返回(2*1 3*4 4*5 5*2)(2 12 20 10)。您不得使用mapcar此功能]

到目前为止我有

(defun vecmul (list list2)
  (cond ((null list) 0)
     (t (cons (* (car list) (car list2))
                 (vecmul (cdr list) (cdr list2))))))

[170]> (setq l '(2 4 6))
(2 4 6)
[171]> (setq r '(1 3 5))
(1 3 5)
[172]> (vecmul l r)
(2 12 30 . 0)

我得到了正确的数字,只是列表添加了“。” 和列表末尾的“0”。我很确定这是因为我没有正确停止递归或没有正确使用条件。我只是不完全确定如何纠正它。

4

2 回答 2

4

你几乎是对的。0但是,当正确的终止为 时,您将使用 终止您的列表nil。此代码有效:

(defun vecmul (list list2)
  (cond ((null list) nil)
     (t (cons (* (car list) (car list2)) (vecmul (cdr list) (cdr list2))))))

当你打电话时(cons 1 2),你得到的缺点单元格被写入(1 . 2)。该符号(1 2 3 4 5)只是 的简写(1 . (2 . (3 . (4 . (5 . nil)))))。如果cdr最后一个 cons 单元格的 是6,不是nil,那么你得到(1 . (2 . (3 . (4 . (5 . 6))))),它缩短为(1 2 3 4 5 . 6)

于 2013-04-02T04:19:09.223 回答
4

尼尔福雷斯特回答了你的问题。

还有一些说明。在 Lisp 中使用现代名称:firstrest.

(defun vecmul (list1 list2)
  (cond ((null list1) nil)
        (t (cons (* (first list1) (first list2))
                 (vecmul (rest list1) (rest list2))))))

如果你有一个简单的真假决定,IF可能会更好。由于涉及列表操作,我将其写为以下而不使用WHEN.

(defun vecmul (list1 list2)
  (if (null list1)
      nil
    (cons (* (first list1) (first list2))
          (vecmul (rest list1) (rest list2)))))

最好在实际代码中使用循环构造或映射。如上所述,递归具有堆栈深度限制。循环没有这种限制。

(defun vecmul (list1 list2)
  (loop for e1 in list1 and e2 in list2
        collect (* e1 e2)))

或者

(defun vecmul (list1 list2)
  (mapcar #'* list1 list2))
于 2013-04-02T07:34:50.777 回答