Adam S
Adam S

Reputation: 9235

Help reducing a Lisp function

I have a Lisp function which returns either the MAX of two values, or the MIN of two values. Right now my code has some relatively complex expressions to evaluate VALUE1 and VALUE2.

(defun treemax (bilist &optional ismin)
  (cond
    ;; Compute minimum
    (ismin (min (COMPLEX_EXPRESSION_1) (COMPLEX_EXPRESSION_2)))
    ;; Compute maximum
    (t (max (COMPLEX_EXPRESSION_1) (COMPLEX_EXPRESSION_2)))))

The problem here is that COMPLEX_EXPRESSION_1 and COMPLEX_EXPRESSION_2 actually take up many many lines of code. I would really like to not repeat them. Is there a more efficient way of calling this?

Essentially what I'm trying to do is a unary-if on functions rather than values. If you are familiar with C or its variants, essentially the concept I'm looking for is:

((ismin ? min : max) COMPLEX_EXPRESSION_1 COMPLEX_EXPRESSION_2)

Whereby I conditionally select which function to send the arguments to. Does this make sense?

Upvotes: 3

Views: 315

Answers (4)

Rainer Joswig
Rainer Joswig

Reputation: 139261

Generally, if you need to write the same code more than once, use a function to capture the code and then call it more than once.

(defun treemax (bilist &optional ismin)
  (cond
     (ismin (min (COMPLEX_EXPRESSION_1) (COMPLEX_EXPRESSION_2)))
     (t     (max (COMPLEX_EXPRESSION_1) (COMPLEX_EXPRESSION_2)))))

-->

(defun treemax (bilist &optional ismin)
  (flet ((f1 () (COMPLEX_EXPRESSION_1))
         (f2 () (COMPLEX_EXPRESSION_2))))
    (cond
       (ismin (min (f1) (f2)))
       (t     (max (f1) (f2))))))

Upvotes: 2

zakovyrya
zakovyrya

Reputation: 9689

(defun treemax (bilist &optional ismin)
    (funcall (if ismin #'min #'max) 
             (COMPLEX_EXPRESSION_1) 
             (COMPLEX_EXPRESSION_2)))

Upvotes: 9

Chuck
Chuck

Reputation: 237060

This is one of the things that Lisp is very good at. You can assign functions to variables and then pass arguments to them with apply or funcall (and in Scheme it's actually even easier). Here's an example:

(defun treemax (bilist &optional ismin)
  (let ((op (if ismin #'min #'max)))
    (funcall op (COMPLEX_EXPRESSION_1) (COMPLEX_EXPRESSION_2))))

(You could of course also just bind COMPLEX_EXPRESSION_1 and COMPLEX_EXPRESSION_2 to variables, but that would still create more repetition.)

Upvotes: 0

C. K. Young
C. K. Young

Reputation: 223033

Surely, this is better:

(defun treemax (bilist &optional (op #'max))
  (funcall op (COMPLEX_EXPRESSION_1) (COMPLEX_EXPRESSION_2)))

Then, simply pass in #'min as argument 2 if you want to use min instead.

(Of course, zakovyrya's answer works too.)

Upvotes: 9

Related Questions