2016-08-17 130 views
2

我試圖在一個庫中使用另一個庫中的效用函數,其中一些建議的方法用(defn)定義,一些用(defprotocol)定義。在Clojure中爲協議方法提供建議

現在我正在使用this library,它使用(alter-var-root)。我不在乎使用哪個庫(或者我是否自己手動推出)。

我現在遇到的問題是協議方法有時可以被建議,有時不能,這取決於我不完全清楚的因素。

  1. 如果我定義了一個協議,然後定義一個類並實現在線該協議,則建議似乎永遠不會工作。我假設這是因爲該類型直接擴展了JVM接口並跳過了變量。

  2. 如果在單個命名空間中,我定義了一個協議,然後告知它的方法,然後將協議擴展到一個類型,建議不是的工作。

  3. 如果在單個命名空間中定義了一個協議,然後將協議擴展爲某種類型,那麼建議協議的方法,建議工作。

我想要做的是找到一種建議的方法,可靠地工作,不依賴於未定義的實現細節。 這可能嗎?

回答

2

Clojure本身不提供任何可靠的建議功能,甚至通過def/defn定義的功能。請看下面的例子:

(require '[richelieu.core :as advice]) 

(advice/defadvice add-one [f x] (inc (f x))) 

(defn func-1 [x] x) 
(def func-2 func-1) 

(advice/advise-var #'func-1 add-one) 

> (func-1 0) 
1 

> (func-2 0) 
0 

形式(def func-2 func-1),VAR func-2的評估後,將含有 VAR func-1(換句話說,它的價值)的結合,所以advice-var不會影響它。

Eventhough,像func-2定義是罕見的,你可能已經注意到或使用下列內容:

(defn generic-function [generic-parameter x y z] 
    ...) 

(def specific-function-1 (partial generic-function <specific-arg-1>)) 
(def specific-function-2 (partial generic-function <specific-arg-2>)) 
... 

如果你的建議generic-function,沒有具體的功能將工作,由於上述特點符合市場預期。

如果建議是你的關鍵,因爲這可能工作,我想一個解決方案如下:因爲Clojure的功能被編譯成Java類,您可以嘗試replace java methodinvoke與曾期望行爲的其他方法(然而,當談論替換協議/接口方法時,事情變得更加複雜:似乎你將不得不在每個實現特定協議/接口的類中替換所需的方法)。

否則,您需要爲每個想要建議的函數顯式包裝。在這種情況下宏可能有助於減少樣板。