почему я не могу объявить пространство имен и метод в do, используя Clojure - PullRequest
4 голосов
/ 25 августа 2009

Я пытаюсь написать макрос в clojure, который устанавливает пространство имен и автоматически добавляет к нему несколько методов. Мой макрос не работал, и я отследил его до утверждения do. Невозможно объявить новое пространство имен в do и сразу же после этого объявить метод в этом пространстве имен. Почему?

Это не работает:

(ns xyz)
(do
  (ns abc)
  (prn *ns*)
  (defn tst[] (prn "test" *ns*)))

(prn "after" *ns*)
(tst)

Это работает (объявление пространства имен перед do):

(ns xyz)
(ns abc)
(do
  (prn *ns*)
  (defn tst[] (prn "test" *ns*)))

(prn "after" *ns*)
(tst)

Спасибо за чтение, Markus

Ответы [ 3 ]

7 голосов
/ 26 августа 2009

На самом деле ваш код работает с Clojure> 1.0, но не полагайтесь на это! Каждая форма верхнего уровня компилируется и затем выполняется:

(ns xyz) ; compiled with current ns / exec sets the current ns to xyz
(do ; the whole form is compiled inthe current ns (xyz) so it defines xyz/tst
  (ns abc)
  (prn *ns*)
  (defn tst[] (prn "test" *ns*)))
; the form above is executed: it sets the new current ns 
; and the value for xyz/tst

(prn "after" *ns*) ; we are in abc
(tst) ; abc/tst doesn't exists

В clojure> 1.0 верхний уровень do развернут, поэтому ваш код теперь эквивалентен:

(ns xyz)
; (do
(ns abc)
(prn *ns*)
(defn tst[] (prn "test" *ns*));)

(prn "after" *ns*)
(tst)
4 голосов
/ 26 августа 2009

Ваш код не делает то, что вы, вероятно, думаете. Функция tst выведет значение * ns *, var, в то время, когда функция run , а не когда определено .

user> (ns foobar)
nil
foobar> (abc/tst)
"test" #<Namespace foobar>
nil
foobar> (ns zelsbot)
nil
zelsbot> (abc/tst)
"test" #<Namespace zelsbot>
nil

То, что вы пытаетесь сделать, уже хорошо предоставлено clojure.contrib.with-ns:

(ns xyz
  (:use clojure.contrib.with-ns))

(with-ns (create-ns 'abc)
  (defn tst [] (print "defined in namespace abc")))

Он оценивает свое тело в пространстве имен, которое вы указали в качестве первого аргумента, что позволяет вам добавлять функции в пространство имен, отличное от текущего.

1 голос
/ 26 августа 2009

Это проблема «времени расширения макроса» против «времени выполнения». Вы хотите, чтобы код в (происходил, когда программа компилируется или когда программа запускается пользователем?
строки (ns ...) расширяются читателем и затем используются компилятором, чтобы решить, куда поместить полученный скомпилированный код.
Если я правильно понимаю, ns устанавливает привязку верхнего уровня переменной var, которая сообщает остальной части компилятора, для какого пространства имен он строит код. В качестве эксперимента попробуйте подумать, в какое пространство имен должно входить выражение (prn ...).

...