Изменить. Я обнаружил частичный ответ на мой собственный вопрос в процессе написания этого, но я думаю, что его можно легко улучшить, поэтому я опубликую его в любом случае. Может быть, там лучшее решение?
Я ищу простой способ определения рекурсивных функций в форме let
, не прибегая к letfn
. Это, вероятно, необоснованный запрос, но причина, по которой я ищу этот метод, состоит в том, что у меня есть набор данных и рекурсивных функций, которые зависят друг от друга так, что требуется много вложенных операторов let
и letfn
.
Я хотел написать рекурсивные функции, которые генерируют такие ленивые последовательности (используя последовательность Фибоначчи в качестве примера):
(let [fibs (lazy-cat [0 1] (map + fibs (rest fibs)))]
(take 10 fibs))
Но в clojure кажется, что fibs
не может использовать свой собственный символ во время привязки. Очевидным способом использования этого метода является letfn
(letfn [(fibo [] (lazy-cat [0 1] (map + (fibo) (rest (fibo)))))]
(take 10 (fibo)))
Но, как я сказал ранее, это приводит к множеству громоздких гнезд и чередующихся let
и letfn
.
Чтобы сделать это без letfn
и используя только let
, я начал писать что-то, что использует то, что я считаю U-combinator (только что услышал о концепции сегодня):
(let [fibs (fn [fi] (lazy-cat [0 1] (map + (fi fi) (rest (fi fi)))))]
(take 10 (fibs fibs)))
Но как избавиться от избытка (fi fi)
?
Именно в этот момент я обнаружил ответ на свой вопрос после часа борьбы и поэтапного добавления бит в комбинатор Q.
(let [Q (fn [r] ((fn [f] (f f)) (fn [y] (r (fn [] (y y))))))
fibs (Q (fn [fi] (lazy-cat [0 1] (map + (fi) (rest (fi))))))]
(take 10 fibs))
Что представляет собой этот комбинатор Q
, который я использую для определения рекурсивной последовательности? Он выглядит как Y combinator без аргументов x
. Это то же самое?
(defn Y [r]
((fn [f] (f f))
(fn [y] (r (fn [x] ((y y) x))))))
Есть ли другая функция в clojure.core или clojure.contrib, которая обеспечивает функциональность Y или Q? Я не могу себе представить, что я только что сделал, было идиоматично...