2017-09-04 61 views
3

我试图在IPv6的唯一网络合作时Clozure CL更换SBCL,但遇到这样的一个错误:如何在仅IPv6网络上使用Clozure CL?

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以覆盖此设置?

回答

2

这可以做到!

首先使原有的化妆插座

(IN-PACKAGE :ccl) 
(DEFPARAMETER original-make-socket #'make-socket) 

的副本然后重新化妆插座。注意:您必须提供所有关键字参数的完整规范。事实上,我只用了你问题中的那些来演示。

(defun make-socket (&key (remote-host "defau.lt") 
         (remote-port 443) 
         (address-family :internet6)) 
    (declare (ignore address-family)) 
    (format t "Calling new make-socket with address-family as internet6!") 
    (funcall original-make-socket 
      :remote-host remote-host 
      :remote-port remote-port 
      :address-family :internet6)) 

这将信号a 可持续错误

类型:go在repl继续。 这将成功修补make-socket。

现在任何对make-socket的调用都将是新的定义。尝试:

(IN-PACKAGE :cl-user) 
(ccl:make-socket :remote-host "ya.ru" :remote-port 443 :address-family :IRRELEVANT) 

另一种方式来做到这一点,将重新定义使插座之前覆盖全局变量*warn-if-redefine-kernel*

(setf *warn-if-redefine-kernel* nil) 

这样可以避免可连续的错误信号,并直接对内核函数进行修补。

5

劝的函数

Common Lisp中的几种实现允许咨询 - 的正常功能(>修补)。建议是一种非标准功能,不同的实现以稍微不同的方式提供。 CLOS泛型函数的一个相关机制是:before,:after和:around方法。

目的是在定义了一个或多个补丁后,在不改变原始源代码的情况下添加一个或多个补丁。

通常这需要函数调用此函数不是内联。在Clozure CL

在Clozure Common Lisp的宏ADVISE

修补功能,可与宏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)