可以分解Clojure函数吗?
虽然我可能会错误地解释同象性的概念,但我把它理解为“代码就是数据” 因此,我可以编写如下代码:可以分解Clojure函数吗?,clojure,homoiconicity,Clojure,Homoiconicity,虽然我可能会错误地解释同象性的概念,但我把它理解为“代码就是数据” 因此,我可以编写如下代码: (def subject "world") (def helo '(str "Hello " subject)) (eval helo) 此时,helo只是数据,但可以像下面这样作为代码执行: (def subject "world") (def helo '(str "Hello " subject)) (eval helo) 返回“Hello world” 我还可以继续将helo作为数据处
(def subject "world")
(def helo '(str "Hello " subject))
(eval helo)
此时,helo
只是数据,但可以像下面这样作为代码执行:
(def subject "world")
(def helo '(str "Hello " subject))
(eval helo)
返回“Hello world”
我还可以继续将helo作为数据处理:
(first helo)
(count helo)
它分别返回str
和3
到目前为止还不错。但是,一旦我将代码包装到函数中,我似乎就失去了将代码视为数据的能力:
(defn helofn [subject]
(str "Hello " subject))
我如何分解helofn?似乎我不能把它当作数据;如果我这样做:
(count helofn)
我得到一个例外:
java.lang.UnsupportedOperationException:此类型不支持计数:user$helofn
是否有其他方法来分解helofn,或者我只是对同象似性期望过高?它看起来没有基于 及 基本上,您可以从.clj文件中定义的函数获取源代码,但是没有可靠的方法来检索仅从该函数构建函数的数据结构
编辑:而且我认为你对同象性的期望太高了。代码本身是数据是的,但不能基于该代码发出的工件检索原始源代码是相当标准的。就像当我有2时,我无法知道它是由(+1)或(-4 2)生成的,同样地,函数是通过调用fn在一些其他数据结构上创建的一段数据,这些数据结构被解释为代码。
defn
只是一个:
如果以定义helo的方式定义helofn,则可以将其视为数据:
(def helofn '(fn [subject]
(str "Hello " subject)))
现在您可以求值并调用此函数:
((eval helofn) "world")
并将其视为数据:
(count helofn)
但是,当您使用defn
宏时,您将helofn
变量与编译函数关联,而不是与它的代码关联
这不仅仅是功能。假设您使用以下代码定义了hello
:
(def helo (str "Hello " subject))
现在,hello
与“hello world”字符串关联,而不是与(str“hello”subject)
代码关联。因此,现在没有办法获得生成此字符串的代码
N.B.如果您想将clojure代码视为数据,您应该查看其。传递给宏的任何代码都被视为数据,宏返回的任何数据都被视为代码。helofn定义是数据,但您可以对其进行求值(就像您显式求值
helo
列表一样)。如果您以与helo
相同的方式处理定义,那么它将保留数据,并且可以接受您想要应用的任何转换:
(def helofndata '(defn helofn [subject]
(str "Hello " subject))
=> (second helofndata)
helofn
=> (eval helofndata)
#'user/helofn
同象性是一个非常强大的概念,我不认为你对它期望太高
defn
实际上是一个使用def
特殊形式定义函数的宏,因此:
(defn sq [x]
(* x x))
实际上相当于:
(def sq (fn ([x] (* x x))))
因此defn
这里接收argssq[x](*x)
,然后构建列表(def sq(fn([x](*x)))
,将其作为宏的结果返回,然后进行求值。这一切都是通过defn
宏对列表、贴图、向量、符号等进行操作完成的
在Clojure中无法获得定义函数的原始符号列表,这与Clojure中所有代码都是编译的有关。这就是为什么在REPL中计算(fn[x]1)
会返回类似#
。但是,正如a中所提到的,所计算的代码是数据
也许我在这方面做得太过分了,但是如果您想为您定义的每个函数创建数据,您可以通过创建自己的自定义宏将其添加到元数据中
下面是这样一个宏的简单实现:
(defmacro defn* [x & body ]
(let [form `'~&form
x (vary-meta x assoc :form form)]
`(defn ~x ~@body)))
;=> #'user/defn*
(defn* sq [x]
(* x x))
;=> #'user/sq
(:form (meta #'sq))
;=> (defn* sq [x] (* x x))
&form
是一个隐式参数(与&env一起),它包含调用宏的整个(未计算的)表单(即编译器计算的数据)
希望这会有所帮助,不会带来更多的困惑