Похоже, вы придумали собственный ответ. Хорошо сделано! Я бы порекомендовал более общую nth
процедуру, которая принимает counter
в качестве аргумента. Это позволяет получить любой элемент в списке ввода
(define (nth lst counter)
(cond ((null? lst) (error 'nth "index out of bounds"))
((= counter 0) (first lst))
(else (nth (rest lst) (- counter 1)))))
Теперь, если вам нужна процедура, которая возвращает только 4-й элемент, мы создадим новую процедуру, которая специализируется на обобщенном nth
(define (fourth-element lst)
(nth lst 3))
Вот и все. Теперь мы проверяем их с вашими входами
(define a `(1 2 3 (4 5) 7))
(define b `(1 2 3))
(define c `((a b)(c d)(e f)(g h)(i j)))
(define d `(a b c))
(fourth-element a) ; '(4 5)
(fourth-element b) ; nth: index out of bounds
(fourth-element c) ; '(g h)
(fourth-element d) ; nth: index out of bounds
Обратите внимание, что когда счетчик выходит за границы, я решил повысить error
вместо того, чтобы возвращать значение ("empty"
), как ваша программа. Возвращение значения делает невозможным узнать, действительно ли вы нашли значение в списке или было возвращено значение по умолчанию. В приведенном ниже примере обратите внимание, что ваша процедура не может различить два входа
(define d `(a b c))
(define e `(a b c ,"empty"))
; your implementation
(fourth-element e) ; "empty"
(fourth-element d) ; "empty"
; my implementation
(fourth-element e) ; "empty"
(fourth-element d) ; error: nth: index out of bounds
Если вы не хотите выдавать ошибку, есть другой способ, которым мы можем кодировать nth
. Вместо возврата n-го элемента мы можем вернуть n-ную пару , в голове которой находится рассматриваемый элемент.
Ниже nth
всегда возвращает список. Если список пуст, элемент не найден. В противном случае n-й элемент - это элемент first
в результате.
(define (nth lst counter)
(cond ((null? lst) '())
((= counter 0) lst)
(else (nth (rest lst) (- counter 1)))))
(define (fourth-element lst)
(nth lst 3))
(define a `(1 2 3 (4 5) 7))
(define b `(1 2 3))
(define c `((a b)(c d)(e f)(g h)(i j)))
(define d `(a b c))
(define e `(a b c ,"empty"))
(fourth-element a) ; '((4 5) 7)
(fourth-element b) ; '()
(fourth-element c) ; '((g h) (i j))
(fourth-element d) ; '()
(fourth-element e) ; '("empty")
Надеюсь, это заставит вас задуматься о domain (тип ввода процедуры) и codomain (тип вывода процедуры).
В общем, вы хотите разработать процедуры, которые имеют естественные описания, такие как:
- "
nth
берет список и число и всегда возвращает список" (лучший)
- "
nth
берет список и число и возвращает элемент списка или вызывает исключение, если элемент не найден" (хорошо, но теперь вы должны обрабатывать ошибки)
Избегайте таких процедур, как
- "
nth
принимает список и число и возвращает элемент списка или строковый литерал "empty"
, если элемент не найден" * (неясный кодомен)
Размышляя о домене и кодомене вашей процедуры, вы понимаете, как будет работать ваша функция, будучи встроенной в различные части вашей программы. Использование многих процедур с плохо определенными доменами приводит к гибельному коду спагетти. И наоборот, четко определенные процедуры могут быть собраны как строительные блоки с небольшим (или без) необходимым кодом клея.