lazy-seq для рекурсивной функции - PullRequest
2 голосов
/ 18 марта 2011

Извините за смутное название, я думаю, я просто недостаточно хорошо понимаю мою проблему, чтобы спросить ее, но здесь идет речь.Я хочу написать рекурсивную функцию, которая принимает последовательность функций для оценки, а затем вызывает себя со своими результатами и так далее.Рекурсия останавливается на некоторой функции, которая возвращает число.

Однако я хотел бы, чтобы функция, вычисляемая в любой точке рекурсии, f, была обернута в функцию s, которая возвращает начальное значение (скажем, 0, или результат другой функции i) при первом вычислении, за которым следует результат вычисления f (так что при следующем вычислении он возвращает ранее оцененный результат и вычисляет следующее значение).Цель состоит в том, чтобы отделить рекурсию, чтобы она могла продолжаться, не вызывая этого .

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

Ответы [ 2 ]

3 голосов
/ 18 марта 2011

Ваше описание напоминает мне некоторые из сокращений ? Сокращения будут выполнять уменьшение и возвращать все промежуточные результаты

user> (reductions + (range 10))
(0 1 3 6 10 15 21 28 36 45)

Здесь (диапазон 10) создается последовательность от 0 до 9. Сокращение применяется + многократно, передавая предыдущий результат + и следующий элемент в последовательности. Все промежуточные результаты возвращаются. Возможно, вам будет полезно взглянуть на источник сокращений.

Если вам нужно встроить тест (проверить значение) в это, это легко сделать с помощью функции if в вашей функции (хотя она не перестанет проходить через seq). Если вы хотите досрочного выхода при условии, что условие истинно, тогда вам нужно написать свой собственный цикл / повтор, который amalloy уже хорошо выполнил.

Мне неприятно это говорить, но я подозреваю, что это также может относиться к Государственной Монаде, кроме IANAMG (Я не парень из монады).

0 голосов
/ 18 марта 2011

Я не понимаю всей вашей цели: многие термины, которые вы используете, расплывчаты. Например, что вы хотите сказать, что хотите оценить последовательность функций, а затем повторить их результаты? Эти функции должны быть функциями без аргументов (thunks), тогда, я полагаю? Но наличие thunk, который сначала возвращает x, а затем возвращает y в следующий раз, когда вы его вызываете, довольно мерзок и полон состояния. Возможно, батут решит часть вашей проблемы?

Вы также ссылались на то, чего хотите избежать, но, похоже, вставили не ту ссылку - это всего лишь ссылка на эту страницу. Если вы хотите избежать переполнения стека, то батут, вероятно, будет хорошим способом справиться с этим, хотя это должно быть возможно только с помощью loop / recur. Это понятие о том, что thunks возвращают x, если они не возвращают y, равно madness , если ваша главная цель - избежать переполнения стека. Не делай этого.

Я пошел дальше и угадал наиболее вероятную конечную цель, которую вы могли бы достичь, и вот моя реализация:

(defn call-until-number [& fs]
  (let [numeric (fn [x] (when (number? x) x))]
    (loop [fs fs]
      (let [result (map #(%) fs)]
        (or (some numeric result)
            (recur result))))))

(call-until-number (fn [] (fn [] 1))) ; yields 1
(call-until-number (fn [] (fn [] 1))  ; yields 2
                   (fn [] 2))
(call-until-number (fn f [] f)) ; never returns, no overflow
...