6

Is there a better way to write the below code with less redundancy?

(cond
((firstFunction str1) (secondFunction str1))
((firstFunction str2) (secondFunction str2))
((firstFunction str3) (secondFunction str3))
((firstFunction str4) (secondFunction str4))
((firstFunction str5) (secondFunction str5))
)

7 Answers 7

10

Traditional Emacs Lisp "in my time we didn't have that new-fangled CL stuff" style:

(catch 'foo
    (dolist (str (list str1 str2 str3 str4))
       (if (firstFunction str)
           (throw 'foo (secondFunction str))))

Traditional Emacs Lisp "when I was at MIT..." style:

(catch 'foo
    (mapc #'(lambda (str)
              (if (firstFunction str)
                  (throw 'foo (secondFunction str))))
        (list str1 str2 str3 str4)))

Traditional Emacs Lisp "and now get off my lawn" style:

(let ((list (list str1 str2 str4)))
   (catch 'foo
       (while list
           (let ((str (pop list)))
               (if (firstFunction str)
                   (throw 'foo (secondFunction str)))))))
8

Wouldn't a loop do it?

(cl-dolist (str (list str1 str2 str3 ...))
  (when (first-function str)
    (cl-return (second-function str))))
2
  • No, @JosephGarvin, the cl-return breaks out of the loop.
    – Omar
    Nov 10, 2015 at 21:09
  • Oh, read too fast, you are correct. Nov 10, 2015 at 22:40
8

Another way using dash.el. You could also do this with cl-lib functions.

(-when-let (found (-find 'firstFunction (list str1 str2 str3 str3)))
  (secondFunction found))

Or, if you know at least one condition will always match:

(secondFunction (-find 'firstFunction (list str1 str2 str3 str3)))
4
  • 1
    Why use dash over cl-lib?
    – PythonNut
    Aug 20, 2015 at 2:46
  • 3
    Honestly I use it so I can type filter instead of cl-remove-if-not. Aug 20, 2015 at 11:07
  • The problem with dash is that by using it you exclude everyone who's more familiar with Emacs Lisp and CL than dash... and that's a lot of people. The fairly minor improvements brought by dash don't justify the cultural incompatibility.
    – jch
    Nov 11, 2015 at 14:26
  • 1
    I think it goes both ways, by using cl-lib you exclude everyone more familiar with most currently popular language than emacs lisp. Any one coming from a language like js, ruby, clojure, and others will immediately understand what a -filter function does and will probably scratch their heads at something so unfortunately named as cl-remove-if-not. Nov 11, 2015 at 15:08
4

Just for fun...

(funcall (lambda (f l) (funcall f l f))
         (lambda (l f) (if l (if (firstFunction (car l))
                                 (secondFunction (car l))
                                 (funcall f (cdr l) f))))
         (list str1 str2 str3 str4 str5))

Or, without lambda tricks:

(defun superCond (l) (if l (if (firstFunction (car l))
                               (secondFunction (car l))
                               (superCond (cdr l)))))
(superCond (list str1 str2 str3 str4 str5))

Or:

(defun superCond (l f1 f2)
  (if l
    (if (funcall f1 (car l))
        (funcall f2 (car l))
        (superCond (cdr l) f1 f2))))
(superCond (list str1 str2 str3 str4 str5) #'firstFunction #'secondFunction)
0
1

One more. Make sure to have pp-macroexpand-last-sexp at hand.

(cl-macrolet ((find-and-use-str (ff sf &rest strs)
                                (cons 'cond
                                      (mapcar (lambda (str)
                                                `((,ff ,str) (,sf ,str)))
                                              strs))))
  (find-and-use-str firstFunc secondFunc "foo" "bar" "baz"))

Please note that the elements of strs will be evaluated twice. In the example, it's ok because they're constant (strings).

1

Another answer, unlike to others this doesn't rely on fancy libraries and esoteric features like catch and throw:

(let ((rest (list str1 str2 str3 str4 str5)))
  (while rest
    (let ((entry (pop rest)))
      (when (firstFunction entry)
        (secondFunction entry)
        (setq rest ())))))

This assumes that the value the original cond expression wasn't used.

1
  • 1
    catch/throw is esoteric?
    – jch
    Nov 12, 2015 at 0:02
1

This macro does the trick.

(defmacro condstrings (f1 f2 &rest strings)
  `(cond ,@(mapcar (lambda (s)
                     `((,f1 ,s) (,f2 ,s)))
                   strings)))

(condstrings firstFunction secondFunction str1 str2 str3 str4 str5)

If it's a concern that the strings are each evaluated twice then you can use the once-only macro defined here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.