Извлечение n-го cdr списка в схеме

#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)