Lisp 获取列表的第n个cdr而不使用第n个cdr

Lisp 获取列表的第n个cdr而不使用第n个cdr,lisp,common-lisp,cdr,Lisp,Common Lisp,Cdr,我是一个普通的Lisp初学者,正在努力完成我的一项作业 我的CS任务之一是创建一个函数,它基本上作为clisp的内置nthcdr函数工作 我们称之为ncdr: (ncdr n L)=>n是我们想要输出的cdr,L是列表 示例: (ncdr 2 '(a b c)) => (c) (ncdr 0 '(a b c)) => (a b c) (ncdr -1 '(a b c)) => nil (ncdr 5 '(a b c)) => nil 所以我的方法是设置一个计数器,并将其

我是一个普通的Lisp初学者,正在努力完成我的一项作业

我的CS任务之一是创建一个函数,它基本上作为clisp的内置nthcdr函数工作

我们称之为ncdr:

(ncdr n L)=>n是我们想要输出的cdr,L是列表

示例:

(ncdr 2 '(a b c)) => (c)
(ncdr 0 '(a b c)) => (a b c)
(ncdr -1 '(a b c)) => nil
(ncdr 5 '(a b c)) => nil
所以我的方法是设置一个计数器,并将其与n进行比较

以下是我想到的条件:

if n < 0 -> nil 
if counter < n -> + 1 counter and (ncdr (cdr list)
if counter = n -> output list
if counter > n -> nil 
如果n<0->nil
如果计数器+1计数器和(ncdr(cdr列表)
如果计数器=n->输出列表
如果计数器>n->nil
这是我想到的…我不认为这是最有效的方法,但是,现在,它不起作用

(defun ncdr (n L &aux counter)
   (setq counter 0)
   (cond
      ((atom L) nil)
      ((< n 0) nil)
      ((< counter n) (+ 1 counter (ncdr n (cdr L))))
      ((eq counter n) L)
      ((> counter n) nil) ))
(解除ncdr(NL和aux计数器)
(setq计数器0)
(续)
((原子L)零)
(计数器n)无)
从我花了几个小时来试验我函数的每一条cond行,我知道这一行并没有按预期工作

((< counter n) (+ 1 counter (ncdr n (cdr L))))
((
我得到一个错误:nil不是一个数字

我觉得我错过了解决这个问题的关键因素。

首先是错误。在:

(+ 1 counter (ncdr n (cdr L))))
实际上,您正在对三个值求和:
1
、变量
计数器的值以及应用于两个参数的函数
ncdr
的结果,当
nil
时,这两个参数会产生错误(例如,您正在求和
(+10 nil)
nil
不是一个数字)

然后,让我们转到程序的逻辑

你的情况基本上是正确的,尽管他们导致了一个可以改进的计划,我们将在后面看到

但是,您在其实现中犯了一个逻辑错误:
计数器应在函数的每次递归调用时更改,增加1,而对于每次调用,您在函数体开始执行时将其重置为零。这是因为即使正确执行,增量也会被赋值取消
(setq计数器0)

我们怎样才能正确地增加这样一个变量?在函数中添加一个新参数
counter
,避免每次都将其重置为零,而只是在初始调用时在开始时将其赋值为零

如何在Common Lisp中实现这一点?使用可选参数,而不是辅助变量,方法如下:

(defun ncdr (n L &optional (counter 0))
  (cond ((atom L) nil)
        ((< n 0) nil)
        ((< counter n) (+ 1 counter (ncdr n (cdr L))))  ; <- Wrong!!! To be corrected
        ((eq counter n) L)
        ((> counter n) nil)))
if the list is empty, return nil
if n is less then 0, return nil
if n is 0, return the list
if n is greater than 0, recur on n-1 and on the cdr of the list
使程序具有以下结构:

(defun ncdr (n L)
  (cond ((null L) nil)
        ((< n 0) nil)
        ((= n 0) L)
        (t (ncdr ...))  ; <- recursive call - to be completed as exercise!
(解除ncdr(n L)
(条件((空L)无)
(
(+ 1 counter (ncdr n (cdr L))))
实际上,您正在对三个值求和:
1
、变量
计数器的值以及应用于两个参数的函数
ncdr
的结果,当
nil
时,这两个参数会产生错误(例如,您正在求和
(+10 nil)
nil
不是一个数字)

然后,让我们转到程序的逻辑

你的情况基本上是正确的,尽管他们导致了一个可以改进的计划,我们将在后面看到

但是,您在其实现中犯了一个逻辑错误:
计数器应在函数的每次递归调用时更改,增加1,而对于每次调用,您在函数体开始执行时将其重置为零。这是因为即使正确执行,增量也会被赋值取消
(setq计数器0)

我们怎样才能正确地增加这样一个变量?在函数中添加一个新参数
counter
,避免每次都将其重置为零,而只是在初始调用时在开始时将其赋值为零

如何在Common Lisp中实现这一点?使用可选参数,而不是辅助变量,方法如下:

(defun ncdr (n L &optional (counter 0))
  (cond ((atom L) nil)
        ((< n 0) nil)
        ((< counter n) (+ 1 counter (ncdr n (cdr L))))  ; <- Wrong!!! To be corrected
        ((eq counter n) L)
        ((> counter n) nil)))
if the list is empty, return nil
if n is less then 0, return nil
if n is 0, return the list
if n is greater than 0, recur on n-1 and on the cdr of the list
使程序具有以下结构:

(defun ncdr (n L)
  (cond ((null L) nil)
        ((< n 0) nil)
        ((= n 0) L)
        (t (ncdr ...))  ; <- recursive call - to be completed as exercise!
(解除ncdr(n L)
(条件((空L)无)
(
对于VisualLisp(AutoCAD):


你的情况……很不好。当
ncdr
返回
nil
时会发生什么?并且
nil
是你在5个案例中的3个案例中返回的。嗯……你有没有想过类似
(cond((null L)nil)((
?另外:不要使用EQ来比较数字。使用EQL或=。你为什么需要N和计数器?我知道我现在把事情弄得特别困难了,谢谢你的帮助!@RainerJoswig EQL对数字不起作用。当类型不同时,EQL返回NIL。
(EQL 1.0 1)=>NIL
,但
(equalp 1.0 1)=>t
(=1.0 1)=>T
你的情况……很不好。当
ncdr
返回
nil
时会发生什么?并且
nil
是你在5个案例中的3个案例中返回的。嗯……你有没有想过类似
(cond((null L)nil)((
?另外:不要使用EQ来比较数字。使用EQL或=。你为什么需要N和计数器?我知道我现在把事情弄得特别困难了,谢谢你的帮助!@RainerJoswig EQL对数字不起作用。当类型不同时,EQL返回NIL。
(EQL 1.0 1)=>NIL
,但
(equalp 1.0 1)=>t
(=1.0 1)=>T
非常感谢您的回答,我现在更了解我的错误了!我没有想到使用n进行递归调用,它工作得非常完美,而且更加优雅。另外,我不太熟悉&aux和&optional之间的区别,我知道optional在这里更适合。非常感谢!非常感谢您的回答,我现在知道了更好地理解我的错误!我没有想到在递归调用中使用n,它工作得非常完美,而且更加优雅。而且我不太熟悉&aux和&optional之间的区别,