Если я делаю следующее в clojure
(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?
Вы можете сделать
(declare sub1a sub1b)
'declare' специально предназначен для создания var без привязки для создания прямых объявлений.
Раз вы объявили имена:
(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) )))
...
Правильное решение написано rkrishnan.
Что касается этой части вопроса:
Это задумано или просто функция работы программы чтения Clojure?
На самом деле это не имеет ничего общего с программой чтения Clojure - это потому, что компилятор преобразует символы в Vars сразу после их встречи (в тех позициях, где они должны «в конечном итоге» быть преобразованы в Var, в отличие от мест, где они называют местных жителей, цитируются или передаются в специальную форму или макрос, конечно) . Это имеет смысл из соображений эффективности: знание того, к какому Var символ относится во время компиляции, позволяет сгенерировать код, который не требует разрешения символов во время выполнения (обычно ему все еще нужно искать значения 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 заставляет вас четко указать на это, если вы действительно думаете, что это то, что вы хотите.