Как использовать Clozure CL только в сети IPv6?
Я пытался заменить SBCL на Clozure CL при работе только в сети IPv6, но обнаружил такую ошибку:
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 ответа
Посоветуйте функцию
Несколько реализаций Common Lisp позволяют рекомендовать (-> исправление) нормальных функций. Консультирование - это нестандартная функция, и различные реализации предоставляют ее немного по-разному. Связанный механизм стандартизирован для универсальных функций CLOS с методами:before,:after и:around.
Цель состоит в том, чтобы добавить один или несколько исправлений к функции после ее определения и без изменения исходного исходного кода.
Обычно для этого требуется, чтобы вызов функции для этой функции не был встроенным.
Макрос ADVISE в Clozure Common Lisp
Функции исправления в Clozure CL можно выполнить с помощью макроса ADVISE
, Смотрите документацию для консультирования.
Допустим, у нас есть функция 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
такой, что назвал арг :D
вызывается с другим значением.
Мы изменяем arglist для вставки нового именованного аргумента после двух обязательных аргументов:
? (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)
Это можно сделать!
Сначала сделайте копию оригинальной розетки
(IN-PACKAGE :ccl)
(DEFPARAMETER original-make-socket #'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))
Это будет сигнализировать о постоянной ошибке.
Тип :go
в ответ, чтобы продолжить. Это успешно исправит 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*
перед переопределением make-socket.
(setf *warn-if-redefine-kernel* nil)
Это позволит избежать продолжительного сигнала об ошибке и исправить патч функции ядра.