2017-07-20 7 views
2

Clojureが新しくなったので、これは本当に明白な質問ですが、役に立たない答えは見つかりません。JavaからClojureを呼び出すときのスコープClojureのスコープ

Clojureを使用してCompiler.eval()を複数回呼び出して結果を計算するSpring Bootを使用してRESTサービスを実装しています。私はすべての要求(定数、関数、グローバル変数など)の間で共有されるはずのClojureのものをいくつか持っています。

クラスパス内でclojure.jarを実行可能なJARとしてこのサービスを実行します。ただし、JVMの観点からは、静的メソッドを使用してClojureにのみアクセスできます。つまり、JVMごとに「Clojureのインスタンス」が1つしかありません。つまり、あるリクエスト中にeval(def a 1)を実行すると、「a」も他のリクエストからも見えるようになります。

質問1:Clojureで動的(リクエストスコープの)変数/シンボルはどこでどのように定義する必要がありますか?

質問2:すべてのリクエストに対して完全に「新しい」Clojureインスタンスが必要だとします。どうすればそれを達成できますか?たとえば、変数が同じ名前で、同じ名前空間にありますが、同じJVM内で異なる値を持つことができますか?私は新鮮なクラスローダーを使用してClojureクラスの全く新しいセットをロードできることは知っていますが、それはひどく面倒です。

+0

)私は 'invoke'を使用し、これは単なるWebリクエストに関連しない – cfrick

答えて

4

Clojureではグローバル変数を使用するべきではありません。グローバルな「状態」をすべての関数で共有する必要がある場合を除き、Clojureでグローバル変数を使用しないでください。それは機能的な言語です(ほとんどの場合)。物事を行うための機能的な方法は、必要なものすべてを引数として渡すことです。これは、参照の透明性を得る方法と、お互いの価値観を見て影響を及ぼす機能を回避する方法です。

なぜ私はSpringBootをこれに使用したいのか分かりませんが、ClojureネイティブWebライブラリの仕組みを見てみることもできます。彼らは通常、何らかの「要求コンテキスト」をハンドラに渡し、必要な情報がすべて格納されます。

たとえばYadaまたはRingです。

あなたの答えを得るには(1):それぞれのリクエストでそれらを渡します。 (2):リクエストごとに新しい値を渡す場合は、その必要はありません。

+0

にその要求ごとの状態を渡したい:​​ING(src/tryclojure/models/eval.cljから抜粋)用clojailを使用してtryclojure does this for requests。 Javaプログラムが複数の独立したClojureプログラムを実行したいとします。私は新しいClojure()。compiler().load(...)を実行できることを期待しています。しかし、すべてのメソッドが静的であるため、別のクラスローダーを使用しないか、独自のJVMでそれぞれを起動しない限り、実際に別のプログラムを分離することはできません。したがって、機能的な言語であるにもかかわらず、基本的に静的な状態でいっぱいです。 IMHO、これは設計上の欠陥です。 – jurez

0

1つのリクエストに対してローカルなグローバルを使用していますが、ClojureでWebサービスを実行するために一般的に推奨される方法ではありませんが、これに対して有効なユースケースがあるとしましょう。そのような使用事例の1つは、tryclj.comのようなオンラインREPLを構築することができます。

リクエストを分離する可能性は、リクエストごとに一時的(ランダム)なネームスペースを作成し、リクエストごとにネームスペースをワイプすることです。 1については

(defn make-sandbox [] 
    (sandbox try-clojure-tester 
      :timeout 2000 
      :init '(do (require '[clojure.repl :refer [doc source]]) 
         (future (Thread/sleep 600000) 
           (-> *ns* .getName remove-ns))))) 
関連する問題