2017-09-04 55 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)