Является ли рекурсия единственным способом написать что-то вроде цикла for на диалекте Racket sdp ("Schreibe dein Programm!"), в котором "(for)" не имеет значения, или есть более "эффективный" или более простой способ сделать так?
Как будет выглядеть ближайший эквивалент цикла C++ for(i = 0 , i < 100, i++)
в коде Racket-sdp?
Как я это делал до сих пор:
(: my-loop (natural -> %a))
(define my-loop
(lambda (i)
(cond
[(< i 100) (my-loop (+ i 1))] ; <-- count up by one till 99 is reached
[else "done"] ; <-- end
)))
(my-loop 0)
Обновлено:
Это скорее общий вопрос. Если бы я написал, скажем, библиотеку raket, содержащую общую функцию, ее можно было бы использовать так:
(for 0 (< i 100) (+ i 1) (func i))
в моих программах, которые представляют собой цикл for, который работает с заданной функцией в качестве «тела», будет ли способ реализовать это правильно?
@ ÓscarLópez Извините, я забыл упомянуть, что я работаю с образовательным диалектом sdp («Schreibe dein Programm!»), который является требованием моего университета (по какой-то причине) для этого проекта. Я отредактировал вопрос соответственно!
Это общий вопрос или вы пытаетесь решить какую-то конкретную проблему? В некоторых случаях вы можете заменить рекурсию такими функциями, как map
, for-each
, filter
или fold
(и некоторые варианты sdp включают их).
Ваш курс, скорее всего, предполагает, что вы научитесь мыслить рекурсивно, а не пытаетесь обойти это и достичь своей зоны комфорта. (Вы можете добавлять циклы и другие структуры управления с помощью макросов — процедур недостаточно — но я не думаю, что в SdP есть макросы.)
[Профессор упомянутого курса здесь.]
Рекурсия действительно является единственным способом выражения повторяющихся вычислений на диалекте Racket, который мы изучаем. (Да, это по замыслу.)
Тем не менее, функции более высокого порядка (и рекурсия) предоставляют все, что вам нужно для создания ваших собственных «циклоподобных управляющих структур». Возьмем, к примеру, следующий HOF, моделирующий петлю repeat-until
:
(: until ((%a -> boolean) (%a -> %a) %a -> %a))
(define until
(lambda (done? f x)
(if (done? x)
x
(until done? f (f x)))))
Обратите внимание, что функция until
является хвостовой рекурсией. Вы можете ожидать, что во время выполнения она действительно будет вести себя как цикл — умный компилятор даже транслирует такую функцию, используя простые jump
инструкции. (Мы обсудим это в следующей главе 12.)
Включает ли этот язык do
? Все еще рекурсия под капотом, но ближе к стилю C для цикла в организации.
Это не. Мы следуем диалекту Schreib Dein Programm (очень вдохновленному HtDP): docs.racket-lang.org/deinprogramm/sdp-vanilla.html
@Shawn do
также не является примитивной формой в Scheme. Он получен из макроса, который решает его с помощью рекурсии
@Sylwester Все еще рекурсия под капотом
Вы можете сделать цикл for высокого порядка. Вот простой пример:
(define (for start end f)
(define (loop i)
(when (< i end)
(f i)
(loop (+ i 1))))
(loop start))
(for 0 10 (λ (i) (displayln i)))
Вы можете сделать это более общим, если вы используете функцию next
вместо (+ i 1)
и используете функцию while-predicate?
вместо (< i end)
.
Самое близкое к циклу
for
в Racket — это... цикл for.