в вашем случае трудно показать, что memoize делает что-то с факториалом, потому что промежуточные вызовы уникальны, поэтому я перепишу несколько надуманный пример, предполагая, что цель состоит в том, чтобы исследовать способы избежать потери стека:
(defn stack-popper [n i]
(if (< i n) (* i (stack-popper n (inc i))) 1))
, который затем может извлечь что-то из памятки:
(def stack-popper
(memoize (fn [n i] (if (< i n) (* i (stack-popper n (inc i))) 1))))
общие подходы к отказу от стека:
использовать хвостовые вызовы
(def stack-popper
(memoize (fn [n acc] (if (> n 1) (recur (dec n) (* acc (dec n))) acc))))
использование батуты
(def stack-popper
(memoize (fn [n acc]
(if (> n 1) #(stack-popper (dec n) (* acc (dec n))) acc))))
(trampoline (stack-popper 4 1))
используйте ленивую последовательность
(reduce * (range 1 4))
Ничто из этого не работает все время, хотя мне еще не приходилось сталкиваться с делом, когда ни один из них не работает. Я почти всегда вначале хожу за ленивыми , потому что я нахожу их наиболее похожими на уловки, затем я направляюсь к хвосту с рекуррентным или трамплином