开发者

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_EX开发者_运维百科PRESSION_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?


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


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


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


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜