2013-03-08 1 views
4

Фон

Я написал взлом для Emacs, который позволяет мне отправить форму Clojure из буфера редактора в буфер REPL. Он работает нормально, за исключением того, что если два буфера находятся в разных пространствах имен, скопированный текст обычно не имеет смысла или, что еще хуже, он может иметь смысл, но имеет другое значение в буфере редактора.Могу ли я преобразовать форму Clojure из одного пакета в другой?

Я хочу преобразовать текст так, чтобы он имел смысл в буфере REPL.

раствора в Common Lisp

В Common Lisp, я мог бы сделать это с помощью следующей функции:

;; Common Lisp 

(defun translate-text-between-packages (text from-package to-package) 
    (let* ((*package* from-package) 
     (form (read-from-string text)) 
     (*package* to-package)) 
    (with-output-to-string (*standard-output*) 
          (pprint form)))) 

И применение образца:

;; Common Lisp 

(make-package 'editor-package) 
(make-package 'repl-package) 

(defvar repl-package::a) 

(translate-text-between-packages "(+ repl-package::a b)" 
           (find-package 'editor-package) 
           (find-package 'repl-package)) 
;; => "(+ A EDITOR-PACKAGE::B)" 

имя пакета квалификации в строка ввода и строка вывода различны - именно то, что необходимо для решения проблемы копирования и вставки текста между пакетами.

(BTW, есть информация о том, как запустить код перевода в общем процессе Lisp и переместить материал между миром Emacs и общим словом Lisp, но я в порядке с этим, и я не особо хочу получить в это здесь)

A Non-Solution в Clojure

Вот прямая трансляция в Clojure:.

;; Clojure 

(defn translate-text-between-namespaces [text from-ns to-ns] 
    (let [*ns* from-ns 
     form (read-string text) 
     *ns* to-ns] 
    (with-out-str 
     (clojure.pprint/pprint form)))) 

И пример использования:

;; Clojure 

(create-ns 'editor-ns) 
(create-ns 'repl-ns) 

(translate-text-between-namespaces "(+ repl-ns/a b)" 
            (find-ns 'editor-ns) 
            (find-ns 'repl-ns)) 
;; => "(+ repl-ns/a b)" 

Таким образом, функция перевода в Clojure ничего не сделала. Это потому, что символы и пакеты/пространства имен в Common Lisp и Clojure работают по-разному.

В общих символах Лиспа относятся к пакету, и определение пакета символа происходит во время чтения.

В Clojure по уважительным причинам символы не принадлежат пространству имен, а определение пространства имен символов происходит во время оценки.

Возможно ли это сделать в Clojure?

Итак, наконец, мой вопрос: можно ли преобразовать код Clojure из одного пространства имен в другое?

+0

Вы просмотрели https://github.com/clojure/tools.reader? – sw1nn

+0

@ sw1nn: Я только что быстро посмотрел. Я не думаю, что там что-то может помочь - ничего о пространствах имен. Это касается разрешения символов, я думаю, что происходит во время оценки, а не для чтения времени. –

+0

Am путать. Почему бы не оценить форму на месте - такие инструменты, как nrepl, сделают это в правильном пространстве имен, так что все работает. Какие результаты вы пытаетесь достичь? Если вам нужен интерактивный реплика, то перемещение текущего REPL в пространство имен текущего буфера также очень просто. –

ответ

1

(Отвечая на мой собственный вопрос ...)

Учитывая, что это не так легко ссылаться на непубличный Варс пространства имен из-за пределы пространства имен, нет простого способа сделать это.

Возможно, взлом возможен, исходя из идеи на http://christophermaier.name/blog/2011/04/30/not-so-private-clojure-functions.Это включает в себя прохождение формы и создание новых символов, которые разрешают новые вары, которые имеют то же значение, что и варсы, упомянутые в исходной форме. Возможно, я когда-нибудь буду исследовать это, но не сейчас.

+0

Я решил написать статью в блоге обо всем этом, и закончил тем, что обычно говорит о различиях между символами в Clojure и Common Lisp. Это [здесь] (http://nomistech.blogspot.co.uk/2013/03/symbols-and-namespaces-in-clojure-and_912.html). –

1

Я не понимаю ваш случай использования, но вот способ преобразования символов из одного пространства имен в другое.

(require 'clojure.walk 'clojure.pprint) 

(defn ns-trans-form [ns1 ns2 form] 
    (clojure.walk/prewalk 
    (fn [f] (if ((every-pred symbol? #(= (namespace %) ns1)) f) 
       (symbol ns2 (name f)) 
       f)) 
    form)) 

(defn ns-trans-text [ns1 ns2 text] 
    (with-out-str 
     (->> text 
      read-string 
      (ns-trans-form ns1 ns2) 
      clojure.pprint/pprint))) 

(print (ns-trans-text "editor-ns" "repl-ns" "(+ editor-ns/a b)")) 
;=> (+ repl-ns/a b) 

Так, editor-ns/a был преобразован в repl-ns/a.

 Смежные вопросы

  • Нет связанных вопросов^_^