2016-08-17 120 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与曾期望行为的其他方法(然而,当谈论替换协议/接口方法时,事情变得更加复杂:似乎你将不得不在每个实现特定协议/接口的类中替换所需的方法)。

否则,您需要为每个想要建议的函数显式包装。在这种情况下宏可能有助于减少样板。