5

あるclojure名前空間でオブジェクトを作成および破棄していて、別の名前空間を調整したいという状況があります。ただし、オブジェクトの破棄時に最初の名前空間が2番目の名前空間を明示的に呼び出す必要はありません。

Javaでは、リスナーを使用できました。残念ながら、基盤となるJavaライブラリは、オブジェクトの破棄に関するイベントを通知しません。もし私がEmacs-Lispにいたら、私はそのトリックを行うフックを使うだろう。

さて、clojureではよくわかりません。RobertHookeライブラリhttps://github.com/technomancy/robert-hookeを見つけました。しかし、これはelisp用語でのdefadviceのようなものです-私は関数を作成しています。ドキュメントの詳細は次のように述べています。

「フックは、制御できない関数を拡張することを目的としています。ターゲット関数を所有している場合は、その動作を変更するためのより良い方法が明らかにあります。」

悲しいことに、私はそれがそれほど明白であるとは思っていません。

もう1つの可能性は、add-watchを使用することですが、これはアルファとしてマークされています。

私は別の明白な解決策を逃していますか?

追加された例:

したがって、最初の名前空間...。

(ns scratch-clj.first
   (:require [scratch-clj.another]))

(def listf (ref ()))

(defn add-object []
  (dosync
    (ref-set listf (conj
               @listf (Object.))))
  (println listf))


(defn remove-object []
  (scratch-clj.another/do-something-useful (first @listf))
  (dosync
     (ref-set listf (rest @listf)))
  (println listf))


(add-object)
(remove-object)

2番目の名前空間

(ns scratch-clj.another)


(defn do-something-useful [object]
   (println "object removed is:" object))

ここでの問題は、scratch-clj.firstが別のイベントを要求し、明示的に削除イベントをプッシュする必要があることです。これは少し不格好ですが、「まだ別の」名前空間があり、それも聞きたい場合は機能しません。

したがって、私は最初の関数をフックすることを考えました。

4

3 に答える 3

1

あなたが説明しているのはコールバックのように聞こえます。

何かのようなもの:

(defn make-object 
  [destructor-fn] 
  {:destructor destructor-fn :other-data "data"})

(defn destroy-object
  [obj]
  ((:destructor obj) obj))

; somewhere at the calling code...

user> (defn my-callback [o] (pr [:destroying o]))
#'user/my-callback
user> (destroy-object (make-object my-callback))
[:destroying {:destructor #<user$my_callback user$my_callback@73b8cdd5>, :other-data "data"}]
nil
user> 
于 2012-11-27T16:15:31.603 に答える
1

このソリューションはお客様の要件に適していますか?

スクラッチ-clj.first:

(ns scratch-clj.first)

(def listf (atom []))
(def destroy-listeners (atom []))
(def add-listeners (atom []))

(defn add-destroy-listener [f]
  (swap! destroy-listeners conj f))

(defn add-add-listener [f]
  (swap! add-listeners conj f))

(defn add-object []
  (let [o (Object.)]
   (doseq [f @add-listeners] (f o))
   (swap! listf conj o)
   (println @listf)))

(defn remove-object []
  (doseq [f @destroy-listeners] (f (first @listf)))
  (swap! listf rest)
  (println @listf))

一部のリスナー:

(ns scratch-clj.another
  (:require [scratch-clj.first :as fst]))

(defn do-something-useful-on-remove [object]
  (println "object removed is:" object))

(defn do-something-useful-on-add [object]
  (println "object added is:" object))

Initバインド:

(ns scratch-clj.testit
  (require [scratch-clj.another :as another]
           [scratch-clj.first :as fst]))

(defn add-listeners []
  (fst/add-destroy-listener another/do-something-useful-on-remove)
  (fst/add-add-listener another/do-something-useful-on-add))

(defn test-it []
  (add-listeners)
  (fst/add-object)
  (fst/remove-object))

テスト:

(test-it)
=> object added is: #<Object java.lang.Object@c7aaef>
   [#<Object java.lang.Object@c7aaef>]
   object removed is: #<Object java.lang.Object@c7aaef>
   ()
于 2012-11-27T17:41:11.730 に答える
0

だから、これがモバイトの提案に続く私の最終的な解決策です。もう少し作業が必要ですが、将来的にはこれが必要になると思います。

すべての助けをありがとう

;; hook system
(defn make-hook []
  (atom []))

(defn add-hook [hook func]
  (do
    (when-not
        (some #{func} @hook)
      (swap! hook conj func))
    @hook))

(defn remove-hook [hook func]
  (swap! hook
         (partial
          remove #{func})))

(defn clear-hook [hook]
  (reset! hook []))

(defn run-hook
  ([hook]
      (doseq [func @hook] (func)))
  ([hook & rest]
      (doseq [func @hook] (apply func rest))))

(defn phils-hook []
  (println "Phils hook"))

(defn phils-hook2 []
  (println "Phils hook2"))


(def test-hook (make-hook))
(add-hook test-hook phils-hook)
(add-hook test-hook phils-hook2)
(run-hook test-hook)
(remove-hook test-hook phils-hook)
(run-hook test-hook)
于 2012-11-27T22:09:50.673 に答える