2015-04-17 5 views
3

Ниже приведен пример:Круговое определение в Clojure

(defn f1 [] (lazy-seq (cons 0 (f2)))) 
(defn f2 [] (lazy-seq (cons 1 (f3)))) 
(defn f3 [] (lazy-seq (cons 2 (f1)))) 

В Haskell эквивалент приведенного выше пример будет производить ленивую последовательность [0, 1, 2, 0, 1, 2, ... ], но в clojure это приведет к исключению CompilerException, потому что f2 не может быть разрешен.

Есть ли способ обойти это?

+0

возможно дубликат [Must Clojure кольцевых структур данных включают конструкции, как реф? ] (http://stackoverflow.com/questions/11568036/must-clojure-circular-data-structures-involve-constructs-like-ref) – galdre

ответ

8

использование declare для создания вперед декларации

user> (declare f1) 
#'user/f1 
user> (declare f2) 
#'user/f2 
user> (declare f3) 
#'user/f3 

или как миниатюрное указывает:

user> (declare f1 f2 f3) 
#'user/f3 

работает хорошо

user> (defn f1 [] (lazy-seq (cons 0 (f2)))) 
#'user/f1 
user> (defn f2 [] (lazy-seq (cons 1 (f3)))) 
#'user/f2 
user> (defn f3 [] (lazy-seq (cons 2 (f1)))) 
#'user/f3 

тогда вы получите ваш рекурсивный ленивую последовательность:

user> (take 20 (f3)) 
(2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0) 
+0

neet Мне также нравится, что лучше, я отредактирую, чтобы использовать это вместо этого, спасибо –

+1

Это была моя привычка с C++ объявлять * все * сущности в верхней части файла заголовка. Затем вы можете определить их в любом порядке, какой бы он ни был, однако они взаимно рекурсивные. Я вижу, что люди делают то же самое с пространствами имен clojure. Возможно, пространство имен должно иметь синтаксическое присутствие, тогда компилятор мог бы это сделать для нас. – Thumbnail

+3

Жестко с нынешним однопроходным компилятором, и компилятор с двумя проходами трудно согласовать с возможностью побочного расширения макросов, среди прочих проблем –

8

Если вы просто хотите, чтобы произвести ленивую последовательность, вы можете определить кучу взаимно рекурсивных функций локально с помощью letfn:

(letfn [(f1 [] (lazy-seq (cons 0 (f2)))) 
     (f2 [] (lazy-seq (cons 1 (f3)))) 
     (f3 [] (lazy-seq (cons 2 (f1))))] 
    (f1)) 

=> (0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 ... 
Смежные вопросы