我想获取列表中任何元素的位置,如果元素不在列表中,则获取nil。我做了:
(defun myposition (letter list)
(cond
((atom list) nil)
((equal (car list) letter) 0)
((null (car list)) (myposition letter))
(t (1+ (myposition letter (cdr list)))) ) )
(myposition 'k '(g h i j k l)
4
(myposition 'p '(g h i j k l)
nil is not a number
当我替换((atom list) nil)
par ((atom list) 0)
时,我得到6而不是
(myposition 'p '(g h i j k l)
6
答案 0 :(得分:0)
在第一个示例中,您的函数将递归计算1+1+1+1+0 = 4
以查找正确的结果。
在第二个示例中,它将遍历整个列表,每个(非匹配)元素添加1,最后添加 nil
。所以它实际上计算1+1+1+1+1+1+nil
,这是不正确的,因为nil
不是数字,因此是错误消息。如果您将nil
替换为零,则会计算1+1+1+1+1+1+0
这是错误的。
所以你的基本问题是你递归地添加1
,并且到达列表的末尾,你想要扔掉你在那之前计算的内容。但是你有一个额外的待处理,你无法逃脱。
最简单的方法是从递归到尾递归解决方案,这在技术上是简单的goto
。这里的添加是通过递增一个变量来完成的,而不是通过展开调用堆栈来完成,这样可以很容易地丢弃之前添加的结果,只返回nil
,因为没有待添加的。{/ p>
(尾部)递归解决方案可能是:
(defun myposition (letter lst)
(labels ((sub (lst pos)
(cond
((null lst) nil)
((equal (car lst) letter) pos)
(t (sub (cdr lst) (1+ pos))))))
(if (atom lst) nil (sub lst 0))))
这可以在Common Lisp中使用,但从技术上讲,如果你的实现没有tail call optimisation,它可能仍会为大型列表打击堆栈。这就是为什么Common Lisp更喜欢迭代解决方案,例如使用loop
宏:
(defun myposition (letter lst)
(when (consp lst)
(loop for c in lst for i from 0
when (equal c letter) return i)))