Clojure 传递变量和元数据
我编写了一个用于调试的简短函数:Clojure 传递变量和元数据,clojure,scope,Clojure,Scope,我编写了一个用于调试的简短函数: (defn printvar "Print information about given variables in `name : value` pairs" [& vars] (dorun (map #(println (name %) ":" (eval %)) vars))) 然后我试着测试它: (defn -main [arg1 arg2] (def moustache true) (def answer 4
(defn printvar
"Print information about given variables in `name : value` pairs"
[& vars]
(dorun (map #(println (name %) ":" (eval %)) vars)))
然后我试着测试它:
(defn -main [arg1 arg2]
(def moustache true) (def answer 42) (def ocelots-are "awesome!")
(printvar 'moustache 'answer 'ocelots-are)
(printvar 'arg1 'arg2))
但是遇到了一些令人困惑的行为:
$ lein repl
> (-main "one" "two")
# moustache : true
# answer : 42
# ocelots-are : awesome!
# CompilerException java.lang.RuntimeException: Unable to resolve symbol: arg1 in this context, compiling:(/tmp/form-init4449285856851838419.clj:1:1)
$ lein run "one" "two"
# Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: moustache in this context, compiling:(/tmp/form-init4557344131005109247.clj:1:113)
通过进一步试验,我发现:
(defn -main [arg1 arg2]
(meta #'arg1))
# Exception in thread "main" java.lang.RuntimeException: Unable to resolve var: arg1 in this context, compiling:(dict_compress/core.clj:9:11)
(defn -main [arg1 arg2]
(def arg1 arg1)
(meta #'arg1))
# {:ns #<Namespace dict-compress.core>, :name arg1, :file dict_compress/core.clj, :column 2, :line 10}
(defn-main[arg1 arg2]
(meta#'arg1))
#线程“main”java.lang.RuntimeException中的异常:无法在此上下文中解析var:arg1,正在编译:(dict_compress/core.clj:9:11)
(defn-主[arg1 arg2]
(def arg1 arg1)
(meta#'arg1))
#{:ns#,:name arg1,:file dict_compress/core.clj,:column 2,:line 10}
现在我完全糊涂了
当您执行(f'var)
和(f var)
时,您到底在传递什么
为什么从REPL运行与直接运行时会有不同的行为
收到的参数和定义的变量之间有什么区别
如何修复我的代码
我的调试方法是否错误?内部
printvar
定义的Var小胡子答案和ocelot是否正确打印,因为def
将它们定义为“全局变量”
这意味着printvar函数可以“看到”一个小胡子
这样想,这是可行的:
(def moustache 43)
(defn printvar []
(println moustache)
(defn main [arg1]
(printvar))
这不起作用:
(defn printvar []
(println arg1))
(defn main [arg1]
(printvar))
这正是您要做的,将参数名传递给eval对参数范围没有任何作用(printvar
将无法看到它)
您的代码有几个问题:
- 您不应该在函数中定义,本地绑定是用
let
<如果你想<代码> EVA/COD>你需要考虑你正在评估的范围。
为了详细说明@Guillermo的评论,这里有一个宏,可以打印任何变量,无论是本地变量还是全局变量
(defmacro printvar
([])
([v & more]
`(let [v# ~v]
(println '~v "=" v#)
(when (seq '~more)
(printvar ~@more)))))
使用此选项,您可以尝试以下顺序:
user> (def glob-var "foo")
#'user/glob-var
user> (defn -main [loc1 loc2]
(printvar glob-var loc1 loc2))
#'user/-main
user> (-main "bar" 42)
glob-var = foo
loc1 = bar
loc2 = 42
nil
user>
参数在函数环境中绑定到其参数。它们不是var
s,只是标签。除了没有元数据之外,参数与变量有何不同?这是正常的,还是仅仅是一个Clojure事件?参数总是值。如果传入变量,则该值可以是var
类型。例如,如果调用(printvar#'arg1)
,则传递的是变量,而不仅仅是它的值。不起作用的是(printvar arg1)
,因为printvar
传递的是arg1
的值,而不是变量本身。是的,您调试错误。对。所以,moustache
是一个变量,的moustache
只是一个文本?有什么方法可以通过元数据传递变量,或者我需要使用宏来解决这个问题吗?“moustach是一个符号而不是文本,如果你想从符号中获取值,你可以执行(var get(ns resolve*ns*'moustach))
,但是你仍然无法“查看”printvar函数中的arg1
参数不在范围内,因为它不在范围内。如果将printvar
更改为宏,它可能会起作用,因为它会在范围内扩展#moustach
是访问变量本身的标准方式