在仅限IPv6的网络中工作时,我尝试用Clozure CL替换SBCL,但是遇到了这样的错误:
MIGRATIONS> (ignore-errors (ccl:make-socket :remote-host "ya.ru" :remote-port 443))
NIL
#<CCL:NO-APPLICABLE-METHOD-EXISTS #x302005215E5D>
MIGRATIONS> (ignore-errors (ccl:make-socket :remote-host "ya.ru" :remote-port 443 :address-family :internet))
NIL
#<CCL:NO-APPLICABLE-METHOD-EXISTS #x3020052549AD>
MIGRATIONS> (ignore-errors (ccl:make-socket :remote-host "ya.ru" :remote-port 443 :address-family :internet6))
#<BASIC-TCP-STREAM ISO-8859-1 (SOCKET/16) #x3020051D4A9D>
问题在于,许多使用
CCL:MAKE-TCP-SOCKET
的库都没有指定地址族或:internet
。有没有一种方法可以在运行时修补
ccl:make-socket
以覆盖此设置? 最佳答案
建议功能
Common Lisp的几种实现允许建议(->修补)正常功能。咨询是一项非标准功能,不同的实现方式以稍微不同的方式提供它。通过:before,:after和:around方法为CLOS泛型函数标准化了一种相关的机制。
目的是在定义一个函数后,不更改原始源代码的情况下,向该函数添加一个或多个补丁。
通常,这要求不内联对此函数的函数调用。
Clozure Common Lisp中的宏ADVISE
Clozure CL中的修补功能可以通过宏ADVISE
完成。请参阅advising的文档。
假设我们有一个函数FOOBAR
:
? (defun foobar (a b &key c (d :foobar)) (list a b c d))
FOOBAR
FOOBAR
在TEST
内部被调用:? (defun test (a) (foobar a 20 :c 30))
TEST
? (test 10)
(10 20 30 :FOOBAR)
现在,我们想对
FOOBAR
进行修补,以使名为arg :D
的值被调用为不同的值。我们将arglist更改为在两个必需的args之后插入新的命名参数:
? (advise foobar (let ((arglist (list* (first arglist)
(second arglist)
:d :ipv6
(cddr arglist))))
(:do-it)) ; calling the original function
:when :around ; advise around it
:name :ipv6) ; the name of this advise
#<Compiled-function (CCL::ADVISED 'FOOBAR) (Non-Global) #x3020010D1CCF>
现在我们可以调用我们的
TEST
函数,它将调用建议的函数FOOBAR
。? (test 10)
(10 20 30 :IPV6)
为CCL提供建议:MAKE-SOCKET
您可以为
CCL:MAKE-SOCKET
写类似的建议。未经测试:
(advise ccl:make-socket (let ((arglist (list* :address-family
:internet6
arglist)))
(:do-it))
:when :around
:name :internet6)