覆盖/重载+操作符来操作普通的lisp向量



我希望重载+操作符来处理常见的lisp向量——就像处理线性代数中的向量一样。是否有可能使用+操作符重载?

这是我想要的定义:

 (defmethod + ((v1 vector) (v2 vector))

提前感谢所有的帮助!

如果我要这样做,我会从在一个单独的包中开始。然后,我将编写一个使用二进制操作符的通用函数:

(defun + (&rest addends)
  (reduce #'binary+ (cdr addends) :initial-value (car addends)))
(defgeneric binary+ (addend1 addend2))

然后你可以在泛型函数binary+上定义方法,允许你添加两个向量,一个向量和一个标量,…

一个合适的包装生成宏:

(defmacro define-operator (op &key (binary-signifier :binary) (package *package*)
  "Defines a generic operator OP, being essentially a reduce operation using
   a generic function whose name is a concatenation of BINARY-SIGNIFIER and OP."
  (let ((op op)
        (binary (intern (concatenate 'string
                                          (string  binary-signifier)
                                          (string op))
                        package)))
    `(progn
       (defun ,op (&rest args)
          (reduce (function ,binary) (cdr args) :initial-value (car args)))
       (defgeneric ,binary (arg1 arg2)))))

然后你可以定义方法,正如Joshua Taylor的回答:

(defmethod binary+ ((x number) (y number))
  (cl:+ x y))
(defmethod binary+ ((x vector) (y vector))
  (map 'vector 'cl:+ x y))
(defmethod binary+ ((x list) (y list))
  (map 'list 'cl:+ x y))

这是vatiine的答案的扩展,但有一些更多的细节,使实现更清晰:

(defpackage #:generic-arithmetic 
  (:use "COMMON-LISP")
  (:shadow "+"))
(in-package #:generic-arithmetic)
(defun + (&rest addends)
  (reduce 'binary+ (cdr addends) :initial-value (car addends)))
(defgeneric binary+ (addend1 addend2))
(defmethod binary+ ((x number) (y number))
  (cl:+ x y))
(defmethod binary+ ((x vector) (y vector))
  (map 'vector 'cl:+ x y))
(defmethod binary+ ((x list) (y list))
  (map 'list 'cl:+ x y))

(+ 1 1)
;=> 2
(+ #(1 2) #(0 -1))
;=> #(1 1)
(+ '(1 3) '(3 1))
;=> (4 4)

可以重新定义+,如果你先阴影它:

? (shadow '+)
? (defgeneric + (a &rest b))
? (defmethod + ((a number) &rest b) (apply 'cl:+ a b))
? (+ 1 2)
3
? (+ 2 3 4)
9
? (defmethod + ((a string) &rest b) (apply #'cl:concatenate 'string a b))
? (+ "Hello" "World")
"HelloWorld"
? (+ "Hello" " cruel " "World")
"Hello cruel World"
? (defmethod + ((a vector) &rest b) (apply #'map 'vector 'cl:+ a b))
? (let ((v0 #(1 2 3)) (v1 #(4 5 6))) (+ v0 v1))
#(5 7 9)

定义泛型函数+可能不是一个好主意,因为,这个符号是锁定的。CLOS不同于其他语言中的对象系统,比如c++,所以术语"重载"可能不太正确。

实际上,你不需要一个特殊的函数来求和向量,使用map:

CL-USER> (let ((v0 #(1 2 3))
               (v1 #(4 5 6)))
           (map 'vector #'+ v0 v1))
#(5 7 9)

最新更新