Во-первых, это не сито Эратосфена ... подробности смотрите в моем комментарии.
Во-вторых, извинения за закрытое голосование, поскольку ваш вопрос не является точной копией того, на который я указал ... Мой плохой.
Объяснение того, что происходит
Разница, конечно, заключается в том, что вы пытаетесь построить инкрементальное сито, где диапазон, в котором работает вызов remove
, бесконечен, и поэтому невозможно просто обернуть doall
вокруг него. Решение состоит в том, чтобы внедрить одно из «настоящих» инкрементальных СО из статьи, на которую я, похоже, довольно часто ссылаюсь в наши дни - «1011 * Подлинное сито Эратосфена» Мелиссы Э. О'Нил .
Особенно красивая реализация сита Clojure такого рода была написана Кристофом Грандом и доступна здесь для восхищения всех, кто может быть заинтересован. Настоятельно рекомендуется к прочтению.
Что касается источника проблемы, то вопросы, которые я первоначально считал вашими, были дубликатами с пояснениями, которые должны быть вам полезны: см. здесь и здесь . Еще раз извините за необдуманное закрытие голосования.
Почему рекурсия хвоста не поможет
Поскольку в этом вопросе конкретно упоминается, что функция просеивания хвостовой рекурсивна как возможное решение, я подумал, что я хотел бы рассмотреть это здесь: функции, которые преобразуют ленивые последовательности, как правило, не должны быть хвостовыми рекурсивными .
Это очень важный момент, о котором следует помнить, и который сбивает с толку многих неопытных программистов на Clojure (или Haskell). Причина в том, что хвостовая рекурсивная функция необходимости возвращает свое значение только тогда, когда она «готова» - в самом конце вычисления. (Итеративный процесс может в конце любой конкретной итерации либо вернуть значение, либо перейти к следующей итерации.) В отличие от этого, функция, которая генерирует ленивую последовательность, должна немедленно вернуть ленивый объект последовательности, который инкапсулирует биты кода, которые можно попросить произвести головку или хвост последовательности, когда это необходимо.
Таким образом, ответ на проблему суммирования ленивых преобразований состоит не в том, чтобы сделать что-либо хвостовым рекурсивным, а в объединении преобразований. В этом конкретном случае наилучшую производительность можно получить, используя пользовательскую схему для объединения операций фильтрации, основанную на приоритетных очередях или картах (подробности см. в вышеупомянутой статье ).