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:
Code: Select all
(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:
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:
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:
Code: Select all
(defun * (&rest arg)
(if (every #'numberp arg)
(apply #'common-lisp:* arg)
(format nil "~{~a~^ * ~}" arg)))
This is how I've evaluated everything:
Code: Select all
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.