2

有没有办法在 Clojure 运行时序列化函数?我希望能够以序列化格式(可能是 edn,但我对任何事情都持开放态度)通过网络发送无状态(但不是纯)函数。


例如...

如果我prn-str在一个函数上运行,我不会得到我期望/想要的。

user=> (def fn1 (fn [x] (* x 2)))
#'user/fn1
user=> (def data {:test 1 :key "value"})
#'user/data
user=> (defn fn2 [x] (* x 2))
#'user/fn2
user=> (prn-str fn1)
"#object[user$fn1 0x28b9c6e2 \"user$fn1@28b9c6e2\"]\n"
user=> (prn-str data)
"{:test 1, :key \"value\"}\n"
user=> (prn-str fn2)
"#object[user$fn2 0x206c48f5 \"user$fn2@206c48f5\"]\n"
user=> 

我本来想要/期望这样的事情:

user=> (prn-str fn2)
"(fn [x] (* x 2))\n"

或许,

user=> (prn-str fn2)
"(defn fn2 [x] (* x 2))\n"
4

6 回答 6

2

您将不得不使用quote'阻止评估并eval强制评估:

(def fn1 '(fn [x] (* x 2)))
(prn-str fn1) ;;=> "(fn [x] (* x 2))\n"
((eval fn1) 1) ;;=> 2
于 2016-08-03T21:50:49.883 回答
2

Flambo 是 Spark 的 Clojure 包装器,它使用serializable-fn库来序列化函数(Spark 需要)。Spark 是 Spark 的另一个包装器,它通过这个实现 Java 接口 Serializable 的Java 抽象类使用原生 Clojure 函数。

于 2016-08-06T03:14:41.477 回答
1

你基本上有两种选择:

  • 传递源代码(存储为 clojure 数据的 s 表达式)
  • 传递 jar 文件并将它们加载到另一端。

对于第一个选项,您在编译函数时保存源代码(几乎总是在定义函数时),然后将相同的源表达式传递给另一台计算机并让它编译相同的东西。所以首先你可以制作一个表达式向量:

(domain-functions '[(defn foo [x] x)
                    (defn bar [y] (inc y)]

然后您可以将其存储到数据库中,每个客户端都可以将其传递给read它们,然后它们都将具有相同的功能。

第二个选项取决于这样一个事实,即每次定义一个函数时,它都会在 /target 目录中生成一个类文件,然后加载它。然后,您可以同步此目录并将它们加载到另一端。这种方法当然是完全疯狂的,尽管人们在这里做疯狂的事情。我推荐第一种方法


作为个人说明:

我现在正在使用 datomic 执行此操作,并且我采用了使用宏将 git-hash 放入函数名称的做法,所以我绝对知道当我调用函数时,我得到的函数与我看到的相同在编辑器中。当运行所有从同一个数据库中提取的许多实例时,这让您高枕无忧。

于 2016-08-03T22:28:42.790 回答
0

你可以使用clojure.repl/source.

(with-out-str (source filter))

得到一个字符串,或

(read-string (with-out-str (source filter)))

获取clojure列表。

于 2016-08-03T22:24:52.167 回答
0

确实没有什么好的方法,出于充分的理由,简单地将一个函数发送到另一台计算机或将其存储在数据库中可能会导致很多问题,其中最重要的是该函数可能需要其他未启用的函数另一端。

一个更好的主意是坚持数据。与其编写函数,不如将函数的名称写为一个事件,然后甚至可以稍后通过读取数据的任何内容进行翻译。坚持数据,这是惯用的方式。

于 2016-08-04T03:14:40.800 回答
0

在某些时候它不再是 Clojure,因此我们可以任意往返于源代码和机器指令并返回的期望有点偏离。

我们应该能够将函数序列化为字节数组并通过网络发送。我怀疑你需要获取函数的 java.lang.Class 对象,然后通过java.lang.instrument.ClassFileTransformer传递它来获取字节。一旦你有了这些,你可以将它们传递给远程 jvm 上友好的java.lang.ClassLoader 。

于 2016-08-08T10:19:27.140 回答