Нарушение контракта с ракеткой (функция максимальной рекурсии)

Изучу схему / ракетку, так что дайте мне немного свободы.

В настоящее время пытаюсь найти максимальное значение при задании списка без использования встроенной функции max ().

Текущий код:

#lang racket
(provide max-num)
(define (max-num lst)
  (define (helper lst max)
    (displayln lst)
    (displayln max)
    (displayln " ")
    (when (null? max) ; first run
        (helper (cdr lst) (car lst)))
    (if (null? lst)
        max ; then end
        (if (> (car lst) max) ; else compare
            (helper (cdr lst) (car lst)) ; then update max
            (helper (cdr lst) max)))) ; else keep max
  (if (null? lst)
      #f ; then Error
      (helper lst '())) ; else run helper
  )

(max-num '())
(max-num '(1 5 2 4 3))

Вывод через DrRacket:

введите описание изображения здесь

Насколько я могу судить, выходы displayln говорят мне, что я на правильном пути. Тем не менее, в конечном итоге нарушение договора заканчивается реальным? ошибка вместо возврата максимального значения.

Я предполагаю, что (if (null? Lst)) не хочет возвращать «max» в конце и вместо этого подталкивает к ветке else, несмотря на то, что список пуст. Я осмотрелся и отладил около часа, но безрезультатно. Любая помощь будет принята с благодарностью.


person user2980932    schedule 07.06.2018    source источник


Ответы (1)


Вы должны знать, что когда вы это сделаете:

(when test
  do-something)
do-something-else

Всегда do-something-else независимо от того, истинно test или нет. Итак, что происходит, так это то, что первый раунд max равен null?, он выполняет (helper (cdr lst) (car lst))) и возвращает ответ. Затем он отбрасывает этот ответ и переходит к if с max, равным null?, и, наконец, терпит неудачу, когда делает (> (car lst) max), поскольку null? не является числом. В сообщении об ошибке говорится, что ожидалось real?, но получено начальное значение '().

Итак, чтобы подсказать вам, как вам идти, вы должны иметь одно выражение в дополнение к локальным определениям, например.

(if test1
    result1
    (if test2
        result2
        alternative2))

or

(cond (test1 result1)
      (test2 result2)
      (else alternative2))

И, конечно же, поскольку вы знаете, что аргумент не null?, вы можете просто вызвать (helper (cdr lst) (car lst)) вместо передачи пустого списка и полностью удалить when. when и unless предназначены для побочных эффектов, а не для хорошего функционального стиля схемы.

person Sylwester    schedule 07.06.2018
comment
Боже мой, спасибо тебе большое. Все заработало. Надеюсь, Scheme / Racket поможет мне в моих ужасных навыках рекурсии, которые я редко использовал в ООП. - person user2980932; 08.06.2018