在 Scheme 中检索列表的第 n 个 cdr

Retrieve nth cdr of a list in Scheme

我想要 return 列表的第 n 个 cdr。例如,我说 (nth-cdr 3 '(a b c d e)) 并且我会得到 (c d e) 作为输出。我不确定我的代码哪里出了问题。

我的做法是这样的。我会检查 (= num 0) 如果是,我会 return 列表。如果没有,我将递归调用 nth-cdr 并从 numcdr list

中减去 1

代码是这样

(define arbitrary-cdr (lambda (num list)
                        (if (= num 0)
                            '()
                            (arbitrary-cdr (- num 1) (cdr list))
                            )))

但是,当我尝试 (arbitrary-cdr 3 ‘(a b c d e))

时出现此错误
‘: undefined;
 cannot reference an identifier before its definition

我不确定这是什么意思。当我这么说时,这意味着我达到了基本情况并且只想 return 列表。不过我觉得我的逻辑是正确的。

您发布的第一个代码是:

(define arbitrary-cdr
  (lambda (num list)
    (if (= num 0)
        (list)
        (arbitrary-cdr (- num 1) (cdr list)))))

您收到的错误是:

scratch.rkt> (arbitrary-cdr 3 '(a b d c e))
; application: not a procedure;
;  expected a procedure that can be applied to arguments
;   given: '(c e)

问题是您使用 list 作为 arbitrary-cdr 过程的参数;由于Racket是lisp-1,程序没有自己的命名空间,所以这里重新定义list。使用 (list)list 重新定义代码试图调用 ((c e)),但 (c e) 不是过程。

这是一个很好的例子,说明了为什么您应该 使用 list 或其他内置过程标识符作为 Scheme 或 Racket 中您自己的过程定义的参数。你可以在 Common Lisp 中避开这个问题,因为 Common Lisp 是一个 lisp-2,即,有一个单独的函数命名空间。

使用更新后的代码:

(define arbitrary-cdr
  (lambda (num list)
    (if (= num 0)
        '()
        (arbitrary-cdr (- num 1) (cdr list)))))

我没有收到您报告的错误;也许您的代码与您发布的不完全相同。但是,您的代码逻辑存在错误。事实上,一个空列表将总是 returned:

scratch.rkt> (arbitrary-cdr 3 '(a b c d e f))
'()

问题是当达到基本情况时,您应该 return 输入列表,而不是空列表。也就是说,给定 (arbitrary-cdr 0 '(a b c)),您希望结果为 (a b c)。这也意味着你的测试用例是错误的; (arbitrary-cdr 0 '(a b c d e)) --> '(a b c d e)(arbitrary-cdr 3 '(a b c d e)) --> '(d e).

这是您重写的代码,使用 xs 而不是 list 来避免重新定义,并且 returning xs 而不是基本情况下的空列表已达到:

(define arbitrary-cdr
  (lambda (num xs)
    (if (= num 0)
        xs
        (arbitrary-cdr (- num 1) (cdr xs)))))

交互示例:

scratch.rkt> (arbitrary-cdr 0 '(a b c d e))
'(a b c d e)
scratch.rkt> (arbitrary-cdr 1 '(a b c d e))
'(b c d e)
scratch.rkt> (arbitrary-cdr 3 '(a b c d e))
'(d e)