覆盖/重载+运算符以对常见的lisp向量进行操作

时间:2014-08-06 04:01:04

标签: operator-overloading common-lisp override

我希望重载+运算符来处理常见的lisp向量 - 就像线性代数中的向量一样。是否可以使用+运算符重载?

这是我的预期定义:

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

提前感谢所有帮助!

4 个答案:

答案 0 :(得分:5)

如果我这样做,我会先从一个单独的包中开始。然后我会编写一个使用二元运算符的通用函数:

(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 composed of BINARY-SIGNIFIER and the operator."
  (let ((op op)
        (binary (intern (concatenate 'string
                                          (string  binary-signifier)
                                          (string op))
                        package)))
    `(progn
       (defun ,op (&rest args)
          (reduce (function ,binary) (cdr args) :initial-vale (car args)))
       (defgeneric ,binary (arg1 arg2)))))

然后你可以按照约书亚泰勒的答案定义方法:

(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 :(得分:3)

定义泛型函数+可能不是一个好主意,因为这个符号被锁定了。 CLOS与其他语言中的对象系统不同,例如C ++,因此术语“重载”可能不太正确。

实际上,您不需要使用特殊函数来对矢量求和,请使用map

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

答案 2 :(得分:3)

这是Vatine's answer的扩展,但有更多细节可以使实现更清晰:

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

答案 3 :(得分:2)

如果您先隐藏它,可以重新定义+

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