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

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

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

Wouldn't a loop do it?

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

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)))
  • 1
    Why use dash over cl-lib? – PythonNut Aug 20 '15 at 2:46
  • 3
    Honestly I use it so I can type filter instead of cl-remove-if-not. – Jordon Biondo Aug 20 '15 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 '15 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. – Jordon Biondo Nov 11 '15 at 15:08

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


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

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


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
    catch/throw is esoteric? – jch Nov 12 '15 at 0:02

This macro does the trick.

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

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