2017-09-04 4 views
3

J'ai essayé de remplacer SBCL avec Clozure CL lorsque l'on travaille dans le réseau IPv6 uniquement, mais a rencontré une erreur comme ça:Comment utiliser Clozure CL sur un réseau IPv6 uniquement?

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> 

Le problème est que de nombreuses bibliothèques lors de l'utilisation CCL:MAKE-TCP-SOCKET ne spécifiez pas l'adresse familiale ou spécifiez un :internet.

Y a-t-il un moyen de corriger ccl:make-socket lors de l'exécution pour remplacer ce paramètre?

Répondre

2

Cela peut être fait!

d'abord une copie de l'original make-prise

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

redéfinissent Ensuite make-socket. Remarque: Vous devrez fournir la spécification complète pour tous les paramètres de mots-clés. En l'état, je n'ai utilisé que ceux de votre question pour la démonstration.

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

Ce signalera une continuable erreur.

Tapez :go à la place pour continuer. Cela corrigera avec succès make-socket.

Maintenant, tout appel à make-socket sera à la nouvelle définition. Essayez:

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

Une autre façon de le faire, serait de passer outre la variable globale *warn-if-redefine-kernel* avant de redéfinir make-socket. Cela permettra d'éviter le signal d'erreur continuable, et corrigera directement la fonction du noyau.

5

Conseiller une fonction

Plusieurs implémentations de Common Lisp permettent conseiller (->rapiéçage) des fonctions normales. Le conseil est une fonctionnalité non standard et différentes implémentations la fournissent de manière légèrement différente. Un mécanisme connexe est standardisé pour les fonctions génériques CLOS avec: before,: after et: around methods.

Le but est d'ajouter un ou plusieurs correctifs à une fonction, une fois qu'elle a été définie et sans modifier le code source d'origine.

Généralement, cela nécessite que l'appel de fonction de cette fonction ne soit pas en ligne.

La macro CONSEILLE dans Clozure Common Lisp

fonctions Patcher dans Clozure CL peut être fait avec la ADVISE macro. Voir la documentation pour advising.

Disons que nous avons une fonction FOOBAR:

? (defun foobar (a b &key c (d :foobar)) (list a b c d)) 
FOOBAR 

FOOBAR est appelé à l'intérieur TEST:

? (defun test (a) (foobar a 20 :c 30)) 
TEST 

? (test 10) 
(10 20 30 :FOOBAR) 

Nous voulons maintenant patcher FOOBAR tel que nommé arg :D est appelée avec une valeur différente.

Nous changeons le arglist d'insérer le nouvel argument du nom des deux args requis:

? (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> 

Maintenant, nous pouvons appeler notre fonction TEST et il appellera le conseillé fonction FOOBAR.

? (test 10) 
(10 20 30 :IPV6) 

Conseiller pour le CCA: MAKE-SOCKET

Vous pouvez écrire un conseiller similaire pour CCL:MAKE-SOCKET.

Untested:

(advise ccl:make-socket (let ((arglist (list* :address-family 
               :internet6 
               arglist))) 
          (:do-it)) 
     :when :around 
     :name :internet6)