为什么“源”不起作用?

时间:2014-01-12 12:21:14

标签: clojure macros

从REPL(Cloure 1.4.0)我试图使用source宏来显示我的函数的定义 - 但它回复'未找到来源'

我可以在source上使用source这样(并且可以看到它使用source-fn) - 但不确定为什么它不喜欢我的defn x[] "hello"函数定义?

user=> (source source)
(defmacro source
  "Prints the source code for the given symbol, if it can find it.
  This requires that the symbol resolve to a Var defined in a
  namespace for which the .clj is in the classpath.

  Example: (source filter)"
  [n]
  `(println (or (source-fn '~n) (str "Source not found"))))
  nil


    user=> (defn x[] "hello")
    #'user/x
    user=> (source x)
    Source not found
    nil
    user=> 

2 个答案:

答案 0 :(得分:6)

source只能获取类路径中可用的源文件中定义的函数源。它不适用于在REPL中定义的函数。

更准确地说,source通过查找由其参数命名的Var来工作,检查Var上的元数据映射是否包含源信息(所有内容都可以工作:file:line需要密钥),查找元数据映射中指定的文件,打开文件(作为类路径上的资源),跳过多行,最后返回下一个表单后面的文本;有关详细信息,请参阅(source clojure.repl/source-fn)

因此,它适用于存储在Vars中的东西 - 比如函数和宏 - 在类路径中仍然存在的源文件的顶层定义。它不适用于未存储在Vars中的内容,也不适用于存储在Vars中的内容,这些Vars的类路径中不存在后备源。后一种情况可以通过AOT编译和在REPL中定义的东西来实现。

答案 1 :(得分:4)

source使用函数元数据来查找定义函数的文件。然后它读取该文件以查找函数定义,将其转换为String并返回它。

简而言之,(源代码)正在做这样的事情

user> (-> (resolve 'source) 
           meta 
           :file)
"clojure/repl.clj"

repl中定义的函数的元数据不包含有效的源文件。

user=> (meta (resolve 'x))
{:arglists ([]), :ns #<Namespace user>, :name x, :column 1, :line 1, :file "NO_SOURCE_PATH"}

您可以在source-fn功能中看到完整的工作原理。