Can I convert a Clojure form from one package to another?

Background

I wrote a hack for Emacs that allows me to submit a Clojure form from the editor buffer to the REPL buffer. It works fine, except if the two buffers are in different namespaces, the copied text usually doesn't make sense or, even worse, it might make sense, but it has a different meaning in the editor buffer.

I want to convert the text so that it makes sense in the REPL buffer.

Solution in Common Lisp

In Common Lisp, I could do this using the following function:

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

And an example of use:

 ;; Common Lisp (make-package 'editor-package) (make-package 'repl-package) (defvar repl-package::a) (translate-text-between-packages "(+ repl-package::ab)" (find-package 'editor-package) (find-package 'repl-package)) ;; => "(+ A EDITOR-PACKAGE::B)" 

The qualifications of the package name in the input line and output line are different - exactly what is needed to solve the problem of copying and pasting text between packages.

(By the way, there is material on how to run the translation code in the general Lisp process and move the material between the Emacs world and the general Lisp world, but I am fine with this and I don’t really want to get here.)

Not a solution in Clojure

Here's a direct translation to 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)))) 

And an example of use:

 ;; Clojure (create-ns 'editor-ns) (create-ns 'repl-ns) (translate-text-between-namespaces "(+ repl-ns/ab)" (find-ns 'editor-ns) (find-ns 'repl-ns)) ;; => "(+ repl-ns/ab)" 

So the translation function in Clojure did nothing. This is because the characters and packages / namespaces in Common Lisp and Clojure work differently.

In Common Lisp, characters refer to a package, and the definition of a package of characters occurs while reading.

In Clojure, for good reason, characters do not belong in the namespace, and the definition of the character namespace occurs during the evaluation.

Could this be done in Clojure?

So finally, my question is: can I convert Clojure code from one namespace to another?

+4
source share
2 answers

(Answering my question ...)

Given that it's not easy to refer to non-public namespace vars from outside the namespace, there is no easy way to do this.

Perhaps hacking is possible based on the idea of http://christophermaier.name/blog/2011/04/30/not-so-private-clojure-functions . This includes going through the form and creating new characters that allow new vars that have the same meaning as the wars mentioned in the original form. Perhaps I will investigate this later, but not now.

+1
source

I do not understand your use case, but here is a way to convert characters from one namespace to another.

 (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/ab)" )) ;=> (+ repl-ns/ab) 

So editor-ns/a been converted to repl-ns/a .

+1
source

All Articles