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

Spark の Clojure ラッパーである Flambo は、serializable-fnライブラリを使用して関数をシリアル化します (これには Spark が必要です)。Spark のもう 1 つのラッパーである Sparkling は、Java インターフェイス Serializable を実装するこの Java 抽象クラスを通じて、ネイティブの Clojure 関数を使用します。

于 2016-08-06T03:14:41.477 に答える
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 に答える
1

基本的に 2 つの選択肢があります。

  • ソースコードを渡す (clojure データとして保存された s 式)
  • jar ファイルを渡し、反対側にロードします。

最初のオプションでは、関数のコンパイル時 (ほとんどの場合定義時) にソースを保存し、同じソース式を他のコンピューターに渡し、同じものをコンパイルさせます。したがって、最初に式のベクトルを作成できます。

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

次に、これをデータベースに保存し、各クライアントがそれを渡すことができread、すべて同じ機能を持つようになります。

2 番目のオプションは、関数を定義するたびに /target ディレクトリにクラス ファイルが生成され、それがロードされるという事実に依存します。次に、このディレクトリを同期して、反対側にロードできます。もちろん、このアプローチは完全にクレイジーですが、人々はここでクレイジーなことをしています。最初のアプローチをお勧めします


そして、個人的なメモとして:

私は今これを datomic で行っています。マクロを使用して git-hash を関数名に入れるという慣行を採用しているので、関数を呼び出すと同じ関数が得られることを絶対に確実に知っていますエディターで。これにより、すべてが同じ DB からプルされる多くのインスタンスを実行するときに安心できます。

于 2016-08-03T22:28:42.790 に答える
0

本当に良い方法はありません。正当な理由により、単純に関数を別のコンピューターに送信したり、DB に保存したりするだけで多くの問題が発生する可能性があります。もう一方の端。

はるかに優れたアイデアは、データに固執することです。関数を記述する代わりに、関数の名前をイベントとして記述します。そうすれば、後でデータを読み取っているものによって翻訳することもできます。データに固執する、それが慣用的な方法です。

于 2016-08-04T03:14:40.800 に答える