传递变量和元数据

时间:2015-02-09 11:38:54

标签: 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 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}

现在我完全糊涂了。

当您执行(f 'var)(f var)时,您到底传递了什么?

为什么从REPL直接运行时有不同的行为?

收到的论证与定义的变量之间的区别是什么?

如何修复我的代码?

我打算以错误的方式调试吗?

2 个答案:

答案 0 :(得分:2)

printvar内部,moustache answerocelots-are正确打印,因为def将其定义为&#34;全局&# 34。

意味着有一个moustache var,printvar函数可以&#34;参见&#34;。

以这种方式思考,这有效:

(def moustache 43)
(defn printvar [] 
   (println moustache)
(defn main [arg1]
    (printvar))

这不起作用:

(defn printvar []
    (println arg1))
(defn main [arg1]
    (printvar))

这正是您正在做的事情,将参数 name 传递给eval对参数范围没有任何作用(printvar无法看到它)

您的代码有几个问题:

  • 你不应该在函数内defing,本地绑定是用let定义的
  • 如果您想要eval,则需要考虑您正在评估的范围。

答案 1 :(得分:0)

只是详细说明@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>