Вам, безусловно, потребуется какой-то способ использования каждого значения, возвращаемого генератором, более одного раза.
В дополнение к предложениям Райнера Йосвига, на ум приходят три подхода.
Кэширование значений
permute-closures
может, конечно, помнить каждое значение, возвращаемое каждым генератором, сохраняя его в списке, и использовать его снова и снова. Этот подход, очевидно, подразумевает некоторые накладные расходы памяти, и он не будет работать очень хорошо, если генерируемые последовательности могут быть бесконечными.
Создание новых генераторов на каждой итерации
В этом подходе вы бы изменили сигнатуру permute-closures
, чтобы принимать в качестве аргументов не готовые к использованию генераторы, а блоки, которые их создают. Ваш пример будет выглядеть так:
(permute-closures (list (lambda () (make-counter 3))
(lambda () (make-counter 3))))
Таким образом, permute-closures
может сбросить генератор, просто воссоздав его.
Создание копий состояний генератора
Вы можете предоставить способ создания копий генераторов вместе с их состояниями. Это своего рода подход № 2 в том, что permute-closures
будет сбрасывать генераторы по мере необходимости, за исключением того, что сброс будет выполнен путем возврата к копии исходного состояния. Кроме того, вы сможете выполнить частичный сброс (т. Е. Выполнить возврат к произвольной точке, а не к началу), что может сделать или не сделать код permute-closures
значительно проще.
Копирование состояний генератора может быть немного проще в языке с продолжениями первого класса (например, Схема), но если все генераторы следуют некоторой предопределенной структуре, абстрагирование ее с помощью макроса define-generator
или некоторых других должно быть возможно в Common Лисп также.