Emacs 通过Slime重新加载多种方法
在Emacs中使用Slime repl进行开发时,我在重新加载多方法时遇到问题 重新定义Emacs 通过Slime重新加载多种方法,emacs,clojure,slime,multimethod,Emacs,Clojure,Slime,Multimethod,在Emacs中使用Slime repl进行开发时,我在重新加载多方法时遇到问题 重新定义defmethod表单效果很好,但是如果我更改分派函数,我似乎无法重新加载defmulti表单。我想我特别添加或删除了分派函数参数 作为一种解决方法,我能够ns取消映射multimethod变量,重新加载defmulti表单,然后重新加载所有defmethod表单 这可能是Clojure实现多方法的一个“限制”,也就是说,为了提高执行速度,我们牺牲了一些活力,但是有没有什么习惯用法或开发实践可以帮助解决这个问
defmethod
表单效果很好,但是如果我更改分派函数,我似乎无法重新加载defmulti
表单。我想我特别添加或删除了分派函数参数
作为一种解决方法,我能够ns取消映射
multimethod变量,重新加载defmulti
表单,然后重新加载所有defmethod
表单
这可能是Clojure实现多方法的一个“限制”,也就是说,为了提高执行速度,我们牺牲了一些活力,但是有没有什么习惯用法或开发实践可以帮助解决这个问题呢?简单的回答是,您处理这个问题的方法是完全正确的。如果您发现自己正在更新一个multimethod,以便特别频繁地更改分派函数,(1)我认为这是不寻常的:-),(2)您可以编写一套函数/宏来帮助重新加载。我画了两个未经测试的(!)宏来帮助下面的(2) 为什么? 然而,首先,简要讨论“为什么”。当前实现的多重方法的分派函数查找不需要同步——分派fn存储在
MultiFn
对象的final
字段中。这当然意味着您不能仅仅更改给定多方法的分派函数——您必须重新创建多方法本身。正如您所指出的,这需要重新注册所有以前定义的方法,这是一个麻烦
当前的行为允许您重新加载包含defmethod
表单的名称空间,而不会丢失所有的方法,代价是在您确实希望这样做的情况下,替换实际的多方法会稍微麻烦一些
如果确实需要,可以通过反射来更改分派fn,但这会带来语义上的问题,特别是在多线程场景中(有关构建后对final
字段进行反射更新的信息,请参阅)
黑客(非反射)
(2)的一种方法是在使用宏重新定义后,按照(未测试的)行自动重新添加方法
另一种设计是使用一个名为的宏和方法重新注册,获取多个名称和主体的序列表,并承诺在执行主体后重新注册方法;这是一张草图(同样,未经测试):
您可以用它来表示(使用方法重新注册[my-multi-1 my-multi-2](要求:重新加载'ns1 ns2))
。不确定这是否值得失去清晰度
(defmacro redefmulti [multifn & defmulti-tail]
`(let [mt# (methods ~multifn)]
(ns-unmap (.ns (var ~multifn)) '~multifn)
(defmulti ~multifn ~@defmulti-tail)
(doseq [[dispval# meth#] mt#]
(.addMethod ~multifn dispval# meth#))))
(defmacro with-method-reregistration [multifns & body]
`(let [mts# (doall (zipmap ~(map (partial list 'var) multifns)
(map methods ~multifns))))]
~@body
(doseq [[v# mt#] mts#
[dispval# meth#] mt#]
(.addMethod @v# dispval# meth#))))