CodeKingPlusPlus
CodeKingPlusPlus

Reputation: 16081

override/overload the + operator to operate on common lisp vectors

I wish to overload the + operator to work on common lisp vectors -- just as it would for vectors in linear algebra. Is it possible to overload with the + operator?

Here is my intended definition:

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

Thanks in advance for all the help!

Upvotes: 4

Views: 3120

Answers (4)

Vatine
Vatine

Reputation: 21268

If I were to do this, I would start by doing it in a separate package. I would then write a general function that uses binary operators:

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

(defgeneric binary+ (addend1 addend2))

Then you can define methods on the generic function binary+ that would allow you to add two vectors, a vector and a scalar, ...

Something that would be a suitable wrapper-generating macro:

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

Then you can define methods, as per Joshua Taylor's answer:

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

Upvotes: 8

Joshua Taylor
Joshua Taylor

Reputation: 85873

This is an extension of Vatine's answer, but with some more detail to make the implementaiton clearer:

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

Upvotes: 5

uselpa
uselpa

Reputation: 18917

It's possible to redefine + if you shadow it first:

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

Upvotes: 4

Mark Karpov
Mark Karpov

Reputation: 7599

It's probably not a good idea to define generic function +, because, well, this symbol is locked. CLOS is different from object systems in other languages, such as C++, so term `overload' is probably not quite correct.

Actually, you do not need a special function to sum vectors, use map:

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

Upvotes: 3

Related Questions