(defpackage :anonymous-generic-function (:use :cl :alexandria) (:export :lambda-generic)) (in-package :anonymous-generic-function) (defmacro defun-ct (name (&rest args) &body body) `(eval-when (:load-toplevel :compile-toplevel :execute) (defun ,name ,args ,@body))) (defun-ct make-anonymous-generic-function (lambda-list methods) (declare (optimize (debug 3))) (let* ((gf (make-instance 'standard-generic-function :lambda-list lambda-list)) (mc (closer-mop:generic-function-method-class gf))) (prog1 gf (loop for (specializers qualifiers body) in methods for (method-lambda initargs) = (multiple-value-list (closer-mop:make-method-lambda gf (closer-mop:class-prototype mc) `(lambda ,lambda-list ,@body) nil)) do (add-method gf (apply #'make-instance mc :function (compile nil method-lambda) :specializers specializers :qualifiers qualifiers :lambda-list lambda-list initargs)))))) (defun-ct take-until (pred list) (loop for (item . rest) on list until (funcall pred item) collect item into items finally (return (values items (cons item rest))))) (defun-ct get-specializers (specialized-lambda-list) (flet ((get-specializer (specializer) (etypecase specializer (symbol (find-class specializer)) (cons (ecase (car specializer) ('eql (closer-mop:intern-eql-specializer (cdr specializer)))))))) (mapcar (lambda (specialized-arg) (if (listp specialized-arg) (get-specializer (cadr specialized-arg)) (find-class t))) specialized-lambda-list))) (defun-ct get-methods (method-definition-list) (loop for (keyword . rest) in method-definition-list unless (eq keyword :method) do (error "method definitions must begin with the :METHOD keyword") collect (multiple-value-bind (qualifiers rest) (take-until #'listp rest) (list (get-specializers (car rest)) qualifiers (cdr rest))))) (defmacro lambda-generic ((&rest lambda-list) &body methods) (let ((methods (get-methods methods))) `(make-anonymous-generic-function ',lambda-list ',methods))) #+null (lambda-generic (a b) (:method ((a integer) (b integer)) (+ a b)) (:method (a b) 2) (:method :after (a b) (format t "~&~d ~d~%" a b)))