1

我不知道这有什么实际用途,我只是想到是否有任何东西可以与defmethodfordefun相媲美lambda?像这样的东西

(defmacro tlambda (args &body body)
  (let* ((gf-name (subseq (write-to-string (gensym)) 2))
         (gf-sym (read-from-string gf-name)))
    `(progn (defmethod ,gf-sym ,args ,@body)
        (prog1 (symbol-function ',gf-sym) (unintern ',gf-sym)))))

(tlambda ((x fixnum)))          ;#<STANDARD-GENERIC-FUNCTION #:G759 (1)>
(funcall (tlambda ((x fixnum)) (* x 2)) 4) ;8
(funcall (tlambda ((x list)) (second x)) '(a s d f)) ;S
(funcall (tlambda ((x string)) (string-upcase x)) "lambda") ;"LAMBDA"
4

2 回答 2

3

我认为这对你展示的形状没有意义。如果类型不匹配会发生什么?如果您只想检查类型,请使用check-type.

Defmethod顺便说一句,并defun没有真正的可比性。 Defun注册一个函数,同时defmethod将一个方法添加到现有的(尽管可能是隐式创建的)泛型函数。您在方法定义中使用的类型用于在调用泛型函数时将(运行时多态性)分派到正确的方法。这种分派的机制在构建时有点昂贵,因此您可能不应该尝试即时(类似于 a generic-lambda)或暂时(类似于 a method-let)执行此操作。

相反,使用 ( e/ c)typecase和类似的方式进行临时调度和check-type检查类型。还有一些用于基于模式的多态性的库(例如 optima、trivia),您可以将其用于更复杂的情况。

于 2020-08-14T15:01:21.797 回答
0

我同意 Svante 的观点,你可能不想要这个。但是,如果您确实想要以您的方式进行操作,那将非常困惑:我根本不明白您在做什么gf-symgf-name但这代表了我认为对符号的一些非常严重的混淆(并且几乎可以肯定是不安全的)。相反,您可以执行以下操作:

(defmacro tlambda (&body cases)
  (let* ((gf-name (gensym)))
    `(progn
       ,@(mapcar (lambda (case)
                   `(defmethod ,gf-name ,@case))
                 cases)
       (symbol-function ',gf-name))))

现在

> (let ((l (tlambda
             ((x y) (cons x y))
             ((x (y integer))
              (declare (ignore x)) y))))
    (values (funcall l 'a 'b)
            (funcall l 'a 1)))
(a . b)
1

我不确定由创建的对象是否tlambda可以被垃圾收集:它们可能是可以的。

于 2020-08-18T11:16:31.133 回答