Почему этот код работает правильно?

#scheme #racket

#схема #ракетка

Вопрос:

Я думал, что следующий код не будет правильно удалять начальные и конечные нули, но это так:

 (define f
  (λ (l)
    (let loop ()                             ; 1 (code line no.)
      (when (= 0 (first l))                  ; 2
        (set! l (rest l))                    ; 3
        (loop))                              ; 4
      (set! l (reverse l) )                  ; 5
      (when (= 0 (first l)) (loop)))         ; 6
    (reverse l)))                            ; 7

(f '(0 0 2 5 0 6 8 9 0 0 0))
  

Вывод:

 '(2 5 0 6 8 9)
  

Я думал, что после удаления начальных нулей список будет перевернут в строке 5; затем из строки 6 он вернется к строке 1 и удалит конечные нули (которые теперь являются ведущими в перевернутом списке). Затем этот список снова изменится (во второй раз в строке 5) и, наконец, он снова изменится (в третий раз) в строке 7.

Поскольку список переворачивается 3 раза, выводом должен быть перевернутый список (без нулей), однако на выходе отображается не перевернутый список. Где недостаток в объяснении?

Комментарии:

1. Опубликованный вами код не тот, на который вы ссылались. Этот код сочетает в себе мутацию и рекурсию, что является неприятной комбинацией для размышлений. Тот, который вы связали, является чисто функциональным.

2. Я изменил код в этой ссылке после того, как обнаружил, что он неисправен. Я удалил ссылку из своего вопроса. Спасибо, что указали на недосмотр.

Ответ №1:

Вы должны помнить, что при возврате цикла программа продолжает выполняться после строки 4. Это происходит для каждого вызова цикла. Итак, если есть n начальных нулей и m конечных нулей reverse , будет вызван n 1 m 1 1 = n m 3 (последний 1 обратный в конце программы), что в примере равно 8.

Однако вы правы в том, что программа не работает как запущенная

 (f '(0 0 2 5 0 6 8 9 0 0))
  

выведет

 '(9 8 6 0 5 2)
  

Комментарии:

1. Следовательно, моя догадка была верной, что этот код не полностью корректен.