首页 > 解决方案 > 在 Scheme 中检索列表的第 n 个 cdr

问题描述

我想返回列表的第 n 个 cdr。例如,我说 (nth-cdr 3 '(a b c d e))我会得到(c d e)输出。我不确定我的代码哪里出错了。

我的做法是这样的。我会检查是否(= num 0)是,我会返回列表。如果没有,我将递归调用并从andnth-cdr中减去 1numcdr list

代码是这样的

(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

我不确定这意味着什么。当我这么说时,这意味着我达到了基本情况并且只想返回列表。我认为我的逻辑是正确的。

标签: schemeracket

解决方案


您发布的第一个代码是:

(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)不是过程。

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

使用您更新的代码:

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

我没有收到您报告的错误;也许您的代码与您发布的代码不完全一样。但是,您的代码逻辑存在错误。实际上,将始终返回一个空列表:

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

问题是当达到基本情况时,您应该返回输入列表,而不是空列表。也就是说,给定(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避免重新定义,并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)

推荐阅读