gpt4 book ai didi

emacs - 通过 Slime 重新加载多方法

转载 作者:行者123 更新时间:2023-12-01 09:35:11 26 4
gpt4 key购买 nike

在 Emacs 中使用 Slime repl 进行开发时,我无法重新加载多方法。

重新定义 defmethod 表单可以正常工作,但如果我更改调度功能,我似乎无法重新加载 defmulti 表单。我想我专门添加或删除了调度函数参数。

作为一种解决方法,我能够 ns-unmap 多方法变量,重新加载 defmulti 表单,然后重新加载所有 defmethod 表格。

大概这是 Clojure 实现多方法的方式的“限制”,即我们牺牲了一些动力来换取执行速度,但是有没有任何习惯用法或开发实践可以帮助解决这个问题?

最佳答案

简短的回答是,您的处理方式是完全正确的。如果您发现自己更新多方法以特别频繁地更改调度功能,(1)我认为这很不寻常:-),(2)您可以编写一套函数/宏来帮助重新加载。我绘制了两个未经测试的 (!) 宏来帮助下面的 (2)。

为什么?

不过,首先简要讨论一下“为什么”。当前实现的多方法的调度函数查找不需要同步——调度 fn 存储在 MultiFn 对象的 final 字段中。这当然意味着您不能只更改给定多方法的调度函数——您必须重新创建多方法本身。正如您所指出的,这需要重新注册所有先前定义的方法,这很麻烦。

当前的行为允许您在其中重新加载带有 defmethod 表单的命名空间,而不会丢失所有方法,但代价是替换实际的多方法会稍微麻烦一些,而这确实是您想要做的.

如果你真的想要,调度 fn 可以通过反射来改变,但这有问题的语义,特别是在多线程场景中(参见 Java Language Specification 17.5.3 了解关于 final 字段的反射更新的信息施工后)。

黑客(非反射)

(2)的一种方法是在重新定义后使用宏(未经测试)自动重新添加方法

(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#))))

另一种设计将使用一个称为with-method-reregistration 的宏,它采用multifn 名称和主体的seqable,并 promise 在执行主体后重新注册方法;这是一个草图(同样,未经测试):

(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#))))

你可以用它来表示 (with-method-reregistration [my-multi-1 my-multi-2] (require :reload 'ns1 ns2))。不确定这是否值得失去清晰度。

关于emacs - 通过 Slime 重新加载多方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9368533/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com