Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
可以分解Clojure函数吗?_Clojure_Homoiconicity - Fatal编程技术网

可以分解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
这里接收args
sq[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一起),它包含调用宏的整个(未计算的)表单(即编译器计算的数据)

希望这会有所帮助,不会带来更多的困惑