【问题标题】:Advising protocol methods in ClojureClojure 中的协议方法建议
【发布时间】:2016-08-17 16:34:38
【问题描述】:
我正在尝试在一个库中使用来自另一个库的实用函数 advise a number of methods,其中一些要建议的方法是用 (defn) 定义的,有些是用 (defprotocol) 定义的。
现在我使用的是this library,它使用的是(alter-var-root)。我不在乎我使用哪个库(或者我是否自己动手)。
我现在遇到的问题是协议方法有时可以建议,有时不能,这取决于我不完全清楚的因素。
如果我定义一个协议,然后定义一个类型并实现该协议in-line,那么建议似乎永远不会起作用。我假设这是因为该类型直接扩展了 JVM 接口并跳过了 var。
-
如果我在单个命名空间中定义了一个协议,然后建议其方法,然后将该协议扩展为一个类型,则建议将不起作用。
-
如果我在单个命名空间中定义一个协议,然后将该协议扩展为一个类型,然后建议该协议的方法,则建议将起作用。
李>
我想做的是找到一种可靠的建议方法,它不依赖于未定义的实现细节。 这可能吗?
【问题讨论】:
标签:
clojure
advising-functions
【解决方案1】:
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 将包含 binding of 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,由于上述特殊性,任何特定功能都不会按预期工作。
如果建议对你来说很重要,作为一个可能工作的解决方案,我会假设如下:由于 Clojure 函数被编译为 java 类,你可以尝试replace java methodinvoke使用具有所需行为的其他方法(但是,在谈论替换协议/接口方法时,事情变得更加复杂:似乎您必须在实现特定协议/接口的每个类中替换所需的方法)。
否则,您需要为每个要建议的函数提供显式包装器。在这种情况下,宏可能有助于减少样板。