2013-04-02 11 views
2

我遇到了代码输出的问题,我想是在检查列表中null的条件时。在Lisp中不使用mapcar将列表中的数字乘以数字(坐标方式)

我想完成的问题是:编写一个函数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”。我非常肯定这是因为我没有停止递归权或者没有正确使用cond。我只是不完全确定如何纠正它。

回答

4

你已经明白了。但是,当正确终止为nil时,您将以0终止您的列表。此代码的工作:

(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)))))的简写。如果最后一个cons单元的cdr6而不是nil,那么您会得到(1 . (2 . (3 . (4 . (5 . 6))))),这会缩短为(1 2 3 4 5 . 6)

4

Neil Forrester回答了你的问题。

还有一些言论。在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)) 
相关问题