Clojure使用kern库时many-till递归解析栈溢出如何解决?
解决Kern库many-till解析器栈溢出的方案
原库中many-till的递归实现属于非尾递归,每一步解析成功后需要等待后续递归调用返回,再将当前结果cons到结果列表头部,输入长度增长时栈帧会线性积累最终触发栈溢出。
可通过尾递归累加器的方案重写many-till,完全消除栈消耗:
(defn many-till [p end] (fn [initial-state] (loop [state initial-state acc []] (let [end-result (end state)] (if (ok? end-result) ;; 如需完全对齐原实现返回列表的行为,可改为 (ok (seq acc) state) (ok acc state) (let [p-result (p state)] (if (error? p-result) p-result (recur (rest-state p-result) (conj acc (value p-result))))))))))
修改说明
- 新增内部loop循环,使用两个状态变量:当前解析状态
state、已解析结果累加器acc - 所有递归调用替换为尾位置的
recur,复用栈帧,不会随输入长度增长产生新的栈帧 - 解析结果直接追加到向量累加器中,无需等待后续调用返回,结束时直接返回累加结果,和原实现的返回值顺序完全一致,通用序列操作完全兼容
你现有业务代码无需修改,替换原many-till定义后即可支持任意长度的输入,不会触发栈溢出。
内容的提问来源于stack exchange,提问作者Unsatisfied Zebra
相关产品推荐
相关产品推荐

