Clojure 中的建议协议方法

Advising protocol methods in Clojure

我正在尝试 advise a number of methods 在一个库中使用另一个库的实用函数,其中一些要建议的方法是用 (defn) 定义的,有些是用 [=11= 定义的].

现在我正在使用 this library,它使用 (alter-var-root)。我不在乎我使用哪个库(或者我是否手动滚动自己的库)。

我现在 运行 遇到的问题是,协议方法有时可以被建议,有时不能,这取决于我不太清楚的因素。

  1. 如果我定义一个协议,然后定义一个类型并实现该协议在线,那么建议似乎永远不会起作用。我假设这是因为该类型直接扩展了 JVM 接口并跳过了 vars.

  2. 如果在单个命名空间中,我定义了一个协议,然后通知它的方法,然后将协议扩展到一个类型,那么通知将不会工作。

  3. 如果我在单个命名空间中定义一个协议,然后将协议扩展为一个类型,然后通知协议的方法,通知 起作用.

我想做的是找到一种可靠的建议方法,并且不依赖于未定义的实现细节。 这可能吗?

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不会影响它。

尽管像 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,none 的特定功能将由于上述特殊性而按预期工作。

如果建议对您来说很重要,作为 可能 可行的解决方案,我假设如下:因为 Clojure 函数被编译为 java class 是的,您可以尝试 replace java method invoke 使用具有所需行为的其他方法(但是,在谈论替换 protocol/interface 方法时,事情变得更加复杂:似乎您必须在实现特定 protocol/interface).

的每个 class 中替换所需的方法

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