开发者

Pre define vars before loading namespace

开发者 https://www.devze.com 2023-03-31 16:43 出处:网络
I have a namespace called some.core with the following, (ns some.core) (defonce name-of-something :a) then from a leiningen plugin I would like to predefine name-of-something before loading the nam

I have a namespace called some.core with the following,

(ns some.core)
(defonce name-of-something :a)

then from a leiningen plugin I would like to predefine name-of-something before loading the namespace so that when the namespace is loaded it is already defined defonce won't define it.


    (eval-in-project project
                     `(do (create-ns 'some.core)
                          (intern 'some.core 'name-of-something开发者_如何学JAVA :b)))

but with the above I keep getting,

Can't intern namespace-qualified symbol

error.


(Updated to take into account the comments below. I leave the original answer under the horizontal rule so as not to remove the context of the comments.)

TL;DR fix:

`(do ... (intern 'some.core '~'name-of-something :b))
                          ; ^- note the '~'

The problem is that the (do ...) form is syntax-quoted (quoted with a backtick, as opposed to a single quote), so symbols inside it get replaced with namespace-qualified variants (after being resolved to determine which namespace they should be qualified with). This excludes symbols which are already namespace-qualified as well as those which contain a dot.

The problematic symbol in the above is name-of-something -- dot-free and unqualified. To rectify the situation, you can replace 'name-of-something with '~'name-of-something; the first quote is included in the output of syntax-quote, the tilde causes the value of the form immediately following it to be included in the expansion of the syntax-quoted region and finally 'name-of-something is the form itself, evaluating to the (unqualified) symbol name-of-something:

If unquoting was unnecessary, replacing the backtick with a single quote would also solve the problem. (The final solution -- mentioned for completeness -- would be to build the form manually: (list 'do ...).)


(Original answer follows.)

You need to change the backtick to single quote:

`(do (create-ns 'some.core) ...)
; change to
'(do (create-ns 'some.core) ...)
^- note the quote

What happens with the backtick, or "syntax quote", is that 'name-of-something gets munged to 'current-namespace/name-of-something, causing intern to complain. (Note that some.core stays untouched -- due to magic treatment of dots in symbols, I believe. The other symbols -- do, create-ns and intern -- are also replaced with namespace-qualified variants, but that doesn't cause any problems.)


Another option is to just load the namespace with the defonce first and then change it with alter-var-root.

Both are pretty crazy workarounds, but what you're asking is pretty crazy to begin with.

0

精彩评论

暂无评论...
验证码 换一张
取 消