Нет в Common Lisp, нет: если вы хотите итеративную конструкцию, вам нужно использовать явно итеративную конструкцию: CL не обещает, что синтаксически-рекурсивные конструкции на самом деле итеративны.loop
не единственная конструкция итерации, однако, и вы, конечно, можете написать свои собственные конструкции итерации и сбора результатов.
Действительно, нет никаких обещаний, что ваша вторая версия не будет переполнять стек в CL: большинство текущихРеализации будут компилировать хвостовые вызовы как итерацию, хотя могут и не обрабатывать это в интерпретируемом коде, но некоторые ограничены своими целями (например, JVM), чтобы они этого не делали.Существовали также основные исторические реализации нативного кода, которые этого не делали (например, Symbolics CL).
Существуют языки семейства Lisp, которые определяют в языке, что хвостовые вызовы являются итерацией, в частности Scheme, и вс такими языками ваша вторая версия будет в порядке.
Что касается вопроса о необходимости построения списков в обратном направлении, а затем наоборот: я думаю, что это неизбежное следствие того, как списки работают в Лиспсе: вы действительно можете собрать тольковсплывающих списков, добавляя их в начало, если вы не хотите изменять существующий список или прибегать к массовому копированию для каждого шага.
Конечно, вы можете скрыть мутацию списка, который вы создаете, засцены, так что вам никогда не нужно знать, что происходит, но это не значит, что это не является ни мутированием структуры, ни построением ее в обратном направлении, а затем наоборот.Так, например, у меня есть конструкция, которая выглядит следующим образом:
(collecting
...
(collect ...)
...)
, которая строит списки вперед, но делает это, сохраняя указатель хвоста и изменяя список, который строит.