Существо, которое вы ищете, это Y * комбинатор.
На основе этой страницы oleg-at-okmij.org Я портировал Y * на Clojure:
(defn Y* [& fs]
(map (fn [f] (f))
((fn [x] (x x))
(fn [p]
(map
(fn [f]
(fn []
(apply f
(map
(fn [ff]
(fn [& y] (apply (ff) y)))
(p p)))))
fs)))))
Классический пример взаимной рекурсивной функции является четным / нечетным, так что вот пример:
(let
[[even? odd?]
(Y*
(fn [e o]
(fn [n]
(or (= 0 n) (o (dec n)))))
(fn [e o]
(fn [n]
(and (not= 0 n) (e (dec n)))))
)
]
(do
(assert (even? 14))
(assert (odd? 333))
))
Выс помощью этих функций можно легко взорвать стек, если вы используете достаточно большие аргументы, поэтому вот его трамплинная версия, например, полнота, которая вообще не использует стек:
(let
[[even? odd?]
(Y*
(fn [e o]
(fn [n]
(or (= 0 n) #(o (dec n)))))
(fn [e o]
(fn [n]
(and (not= 0 n) #(e (dec n)))))
)
]
(do
(assert (trampoline even? 144444))
(assert (trampoline odd? 333333))
))
Y * комбинатор очень полезен для определения взаимных рекурсивных определений монадических парсеров, о которых я скоро опубликую на lambder.com, следите за обновлениями;)
- Lambder