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
是访问变量本身的标准方式