Циклические зависимости функции clojure специально запрещены проектом, или это просто поведение читателя? - PullRequest
7 голосов
/ 08 августа 2010

Если я сделаю следующее в ближайшем будущем

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (sub1b (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (sub1a (- a 1) )))

(println (sub1a 10))

Я получаю следующую ошибку:

java.lang.Exception: Unable to resolve symbol: sub1b in this context

Но если я сделаю следующее:

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (- a 1)))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (- a 1)))

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (sub1b (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (sub1a (- a 1) )))

(println (sub1a 10))

Работает просто отлично.

Это задумано, или это просто функция читателя Clojure?

Ответы [ 2 ]

16 голосов
/ 08 августа 2010

Вы можете сделать

(declare sub1a sub1b)

«Объявить» специально предназначено для создания переменной без привязок для отправки предварительных объявлений.

Один, который вы объявили имена:

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (sub1b (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (sub1a (- a 1) )))

(println (sub1a 10))

Также идиоматическим способом указания условия по умолчанию в cond (для clojure) является использование предложения: else.Это немного отличается от Common Lisp, который использует T (для True).Таким образом, ваш предыдущий код может быть переписан как:

(defn sub1a [a]
  (cond
    (= a 0) 0
    :else (sub1b (- a 1) )))

...
3 голосов
/ 08 августа 2010

Правильное решение опубликовано rkrishnan.

Что касается этой части вопроса:

Это задумано, или это просто функция читателя Clojureработает?

На самом деле это не имеет ничего общего с ридером Clojure - это потому, что компилятор разрешает символы в Vars сразу же после их обнаружения (в тех позициях, где они должны были бы "в конечном итоге" быть разрешеныVar, в отличие от мест, где они называют местных жителей, цитируются или передаются в специальную форму или макрос, конечно).Это имеет смысл с точки зрения эффективности: знание того, к какому Var относится символ во время компиляции, позволяет генерировать код, который не должен разрешать символы во время выполнения (обычно все еще нужно искать значения в Vars, но не сами Vars).Если бы вы действительно хотели, вы могли бы, чтобы ваш код разрешал символы во время выполнения:

(defn sub1a [a]
  (cond
    (= a 0) 0
    :else ((resolve 'sub1b) (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    :else ((resolve 'sub1a) (- a 1) )))

(println (sub1a 10))

; prints 0 and returns nil

Это, однако, приводит к некоторому снижению производительности, которое вряд ли когда-либо оправдано в реальном коде, поэтому Clojure заставляет вас бытьоткровенно об этом, если вы действительно думаете, что это то, что вы хотите.

...