Является функция clojure циклическими зависимостями, конкретно запрещенными дизайном, или это - просто поведение читателя?

Если я делаю следующее в 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?

7
задан hawkeye 8 August 2010 в 10:29
поделиться

2 ответа

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

(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) )))

...
16
ответ дан 6 December 2019 в 09:57
поделиться

Правильное решение написано 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 заставляет вас четко указать на это, если вы действительно думаете, что это то, что вы хотите.

3
ответ дан 6 December 2019 в 09:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: