#scheme #racket
#схема #рэкет
Вопрос:
Я хотел бы вернуть n-й cdr списка. Например, я говорю (nth-cdr 3 '(a b c d e))
, и я бы получил (c d e)
как результат. Я не уверен, где я ошибаюсь в своем коде.
Мой подход заключается в следующем. Я проверю (= num 0)
, если это так, я верну список. Если нет, я буду рекурсивно вызывать nth-cdr
и вычитать 1 из num
и cdr 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
Я не уверен, что это значит. Когда я говорю это, это означает, что я перешел к базовому варианту и просто хотел бы вернуть список. Однако я думаю, что моя логика верна.
Комментарии:
1. В
(arbitrary-cdr 3 ‘(a b c d e))
, вы написали «фигурный» символ кавычки (фактический символ кавычки) вместо «прямого». Это не синтаксическая ошибка, потому что это допустимый идентификатор в схеме.2. Пожалуйста, не заменяйте свой вопрос новым вопросом после того, как вы получили ответ.
Ответ №1:
Первый код, который вы опубликовали, был:
(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)))))
Я не получаю сообщение об ошибке, о котором вы сообщаете; возможно, ваш код не совсем соответствует тому, что вы опубликовали. Но в логике вашего кода есть ошибка. Как бы то ни было, всегда будет возвращен пустой список:
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)