找到原子的位置 - 如果不存在则返回nil

Jon*_*h P 0 lisp recursion position common-lisp

我试图在列表中找到原子的位置.

预期成绩:

(position-in-list 'a '(a b c d e)) 给出0

(position-in-list 'b '(a b c d e)) 给出1

(position-in-list 'Z '(a b c d e)) 没有.

我有一个函数,当项目在列表中时,正确地给出位置:

(defun position-in-list (letter list)
  (cond
    ((atom list)            nil)
    ((eq (car list) letter) 0)
    (t                      (+ 1 (position-in-list letter (cdr list))))))
Run Code Online (Sandbox Code Playgroud)

问题是,当项目不存在时它不返回nil,就好像它达到(atom list)nil它会给出这个错误:*** - 1+: nil is not a number当它取消堆栈时,它会尝试将值添加到nil.

有没有办法调整这个功能(保持相同的结构),以便nil当项目不在列表中时正确返回?

笔记:

  • 我知道库中有一个position函数,但我不想使用它.

  • 我知道我的问题与类似,但我上面提到的问题没有得到解决.

*编辑* 感谢大家的答案.虽然我没有必要的知识来理解你提到的所有建议,但它很有帮助.

我找到了另一个解决我问题的方法:

(defun position-in-list (letter liste)
   (cond
      ((atom liste) nil)
      ((equal letter (car liste)) 0)
      ((position-in-list letter (cdr liste)) (+ 1 (position-in-list letter (cdr liste)))) ) )
Run Code Online (Sandbox Code Playgroud)

Rai*_*wig 5

一种可能的解决方案是使递归函数成为另一个函数的局部函数.最后,一个人将从周围的函数返回 - 因此您不需要NIL从每个递归调用返回结果.

本地递归函数从函数返回

可以使用定义本地递归函数LABELS.

(defun position-in-list (letter list)
  (labels ((position-in-list-aux (letter list)
             (cond
              ((atom list)               (return-from position-in-list nil))
              ((eql (first list) letter) 0)
              (t                         (+ 1 (position-in-list-aux
                                               letter (cdr list)))))))
    (position-in-list-aux letter list)))
Run Code Online (Sandbox Code Playgroud)

RETURN-FROM是可能的,因为从本地函数可以看到返回的函数.

递归函数返回另一个函数

也可以使用CATCH和将控制返回到另一个函数THROW:

(defun position-in-list (letter list)
  (catch 'position-in-list-catch-tag 
    (position-in-list-aux letter list)))

(defun position-in-list-aux (letter list)
  (cond
   ((atom list)               (throw 'position-in-list-catch-tag nil))
   ((eql (first list) letter) 0)
   (t                         (+ 1 (position-in-list-aux
                                    letter (cdr list))))))
Run Code Online (Sandbox Code Playgroud)

测试功能EQL

另请注意,按惯例的默认测试功能EQL不是EQ.这也允许使用数字和字符.