This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Redefinition of function(operator) *

5 posts · 2192 views

I am new to Cl.
I have to define +,-,* and / operators for strings.
so, if the input is :
setf ret (+ 1 2 3 "asd"), I want the output in ret to be "1+2+3+asd". Similarly, for other operators.

I had no issues while redefining +, - and /. But redefining '*' is giving me headaches.

The sample * function:
(defun abc:* (&rest arg)
 (if (isAllNum arg)
  (setf ret (multiple-value-call #'common-lisp:* (values-list arg)))
  ;else
  (if(= (list-length arg) 1)(setf ret (format nil "~a" arg)) (setf ret (format nil "~{~a~^ * ~}" arg))
  )
 )
 ret
)
The package abc uses common-lisp package and I have shadowed and exported opertaors(+, -, *, /).
Except '*' , the rest work fine according to my requirement. I get a name-conflict error for *.
Please suggest a better approach if available.

Re: Redefinition of function(operator) *

Thinking of another approach, I wanted to know if i can redefine an operator for a particular class (like in C++).

Re: Redefinition of function(operator) *

justanoob wrote:I am new to Cl.
I have to define +,-,* and / operators for strings.
so, if the input is :
setf ret (+ 1 2 3 "asd"), I want the output in ret to be "1+2+3+asd". Similarly, for other operators.

I had no issues while redefining +, - and /. But redefining '*' is giving me headaches.
But there should be no difference from defining operators +, -, / and * (except for the obvious).
justanoob wrote:IThe sample * function:
(defun abc:* (&rest arg)
 (if (isAllNum arg)
  (setf ret (multiple-value-call #'common-lisp:* (values-list arg)))
  ;else
  (if(= (list-length arg) 1)(setf ret (format nil "~a" arg)) (setf ret (format nil "~{~a~^ * ~}" arg))
  )
 )
 ret
)
The package abc uses common-lisp package and I have shadowed and exported opertaors(+, -, *, /).
Except '*' , the rest work fine according to my requirement. I get a name-conflict error for *.
Please suggest a better approach if available.
I got no problems defining that function here (except for the variable "ret", which is not defined). Did you export the symbol * from the package abc? I can't thing of any other possible problems.

You took the right approach by creating a new package and shadowing the operators +, -, * and /. But there are a few things that you should change.

First of all, your function does not work correctly if you invoke it with only one string argument:
abc> (* "1")
"(1)"
There is no need for the last if. The call (format nil "~{~a~^ * ~}" arg) will work if arg is a list of only one element.

Second, you are implicitly creating a global function named "ret". This is not good (in CL, it is not defined what exactly will happen in those cases, but that you might learn in another time). You should either create a local variable (using let) or not create any variables at all - the last approach is more lispy in this case, only create variables when they are needed.

Instead of calling (multiple-value-call #'common-lisp:* (values-list arg)), you may use (apply #'common-lisp:* arg) (which does the same thing you were doing).

And last, I don't know how you implemented the function isAllNum, but there is a simple way to implement it using every, like this:
(every #'numberp arg)
This function will call the function #'numberp to every element of arg and test if they all return true.

With the modifications I suggested, here is your function:
(defun * (&rest arg)
 (if (every #'numberp arg)
     (apply #'common-lisp:* arg)
     (format nil "~{~a~^ * ~}" arg)))
This is how I've evaluated everything:
cl-user> (defpackage :abc (:use :cl) (:shadow cl:+ cl:- cl:/ cl:*))
#<package "ABC">
cl-user> (in-package :abc)
#<package "ABC">
abc> (defun * (&rest arg)
 (if (every #'numberp arg)
     (apply #'common-lisp:* arg)
     (format nil "~{~a~^ * ~}" arg)))
*
abc> (* "1")
"1"
abc> (* "1" 2 3 4)
"1 * 2 * 3 * 4"
abc> (* 1 2 3 4)
24
justanoob wrote:Thinking of another approach, I wanted to know if i can redefine an operator for a particular class (like in C++).
Unfortunately, no.

Re: Redefinition of function(operator) *

As you've already discovered, these redefinitions belong in a new package.

The other part of your question hinges on the difference between "a+b+c" in C++ and "(+ a b c)" in CL. In C++, you have 2 calls to "operator+", whereas the CL code has a single call.

To achieve the C++ semantics in CL, try something like
;; define a package
(defpackage :genop (:use :cl) (:shadow '+))
(in-package :genop)

;; define the protocol
(defgeneric operator+ (a b)
  (:documentation "operator overloading for binary +"))
(defun + (&rest args)
  "N-ary +, dispatches to operator+"
  (reduce #'operator+ args))

;; define the overloads
(defmethod operator+ ((a number) (b number))
  (cl:+ a b))
(defmethod operator+ ((a string) (b string))
  (concatenate 'string a b))
(defmethod operator+ ((a number) (b string))
  (format nil "~A~A" a b))
(defmethod operator+ ((a string) (b number))
  (format nil "~A~A" a b))

;; simple tests
(+ 1 2) ;; 3
(+ "a" "b") ;; "ab"
(+ 1 2 "b") ;; "3b"
(+ "a" 1 2) ;; "a12"

Re: Redefinition of function(operator) *

@gugamilare
Thanks for your suggestions and improvements.
@nuntius
Nice one.