-;; TODO: Use MACROLET when it exists
-(defmacro define-variadic-op (operator initial-value)
- (let ((init-sym (gensym))
- (dolist-sym (gensym)))
- `(defun ,operator (&rest args)
- (let ((,init-sym ,initial-value))
- (dolist (,dolist-sym args)
- (setq ,init-sym (,operator ,init-sym ,dolist-sym)))
- ,init-sym))))
-
-(define-variadic-op + 0)
-(define-variadic-op - 0)
-(define-variadic-op * 1)
-(define-variadic-op / 1)
+(macrolet ((def (operator initial-value)
+ (let ((init-sym (gensym))
+ (dolist-sym (gensym)))
+ `(defun ,operator (&rest args)
+ (let ((,init-sym ,initial-value))
+ (dolist (,dolist-sym args)
+ (setq ,init-sym (,operator ,init-sym ,dolist-sym)))
+ ,init-sym)))))
+ (def + 0)
+ (def * 1))
+
+;; - and / work differently from the above macro.
+;; If only one arg is given, it negates it or takes its reciprocal.
+;; Otherwise all the other args are subtracted from or divided by it.
+(macrolet ((def (operator unary-form)
+ `(defun ,operator (x &rest args)
+ (cond
+ ((null args) ,unary-form)
+ (t (dolist (y args)
+ (setq x (,operator x y)))
+ x)))))
+ (def - (- x))
+ (def / (/ 1 x)))
+