2012-06-14 9 views
11

私は少し高価です(データベースを開始する)、私は実際にそれを使用するつもりなら、私はデータベースを作成したいだけです。私は、参照変数(または可能であれば、単純な変数)を使用している(または逆参照された)イベントでその値を評価するだけの参照変数を探しています。概念的には次のようなものです。私はどちらかだけVAR vを使用し、または@vを呼び出し、私はそれは「本当にEXPENSIVE FUNCTION」をプリントアウトして取得し、Vその上から真の価値を持っているClojureには遅延変数がありますか?

(def v (lazy-var (fn [] (do (println "REALLY EXPENSIVE FUNCTION") true)))) 

と将来的には、。ここで重要なことは、変数が参照されるまでfnが評価されなかったことです。必要に応じて、関数は1回だけ評価され、変数の値が計算されます。これはクロージャーで可能ですか?

答えて

25

delayは、このアプリケーションのために完璧になる:

delay- (delay & body)

は、式のボディを受け取り、(と体にそれが強制されて初回のみを呼び出す遅延オブジェクトを生成しますforceまたはderef/@)、結果をキャッシュし、それ以降のすべてのforce呼び出しで返します。

delay呼び出しのボディ内に、Varとして格納されているデータベースハンドルを作成するコードを配置します。その後、DBハンドルを使用する必要があるときはいつでも、このVarを逆参照します。最初の逆参照でボディが実行され、その後の逆参照でキャッシュされたハンドルが戻されます。この目的のために

(def db (delay (println "DB stuff") x)) 

(select @db ...) ; "DB stuff" printed, x returned 
(insert @db ...) ; x returned (cached) 
+1

うん、これを見てみると、なぜ私はその言葉を考えなかったのだろうか? –

6

Clojureの1.3導入memoize機能:

(memoizeのF)

は、参照透明関数のメモ化バージョンを返します。 関数のmemoizedバージョンは、 引数から結果へのマッピングのキャッシュを保持し、同じ引数を持つ呼び出しが頻繁に繰り返されると、より高いメモリを犠牲にしてパフォーマンスが向上します。 使用。あなたの例では

memoizeに存在しない怠惰-VARを置き換える:別の答えは説明しているように

(def v (memoize (fn [] (do (println "REALLY EXPENSIVE FUNCTION") true)))) 
(v) 
=>REALLY EXPENSIVE FUNCTION 
=>true 
(v) 
=>true 

は、(式exprを遅らせる)も仕事をしていません。 dereferencingの遅延に対する追加のコメント - forceとderef/@の違いは、非遅延変数で使用された場合、forceは例外をスローしませんが、deref/@はClassCastExceptionをスローする可能性があります。 "clojure.lang.IDerefにキャストできません"。

関連する問題