The art of replacing long lambdas I: llamas, anaphorics, and combinators

Lambdas in Emacs Lisp can look long and noisy. Are there alternatives?

A library for shortening lambdas

Your lambdas can be made short and sweet with llama.

Here's a simple example:

(lambda (str) (upcase (reverse str)))  ; regular lambda
(##upcase (reverse %))                 ; llama

The library can deal with arbitrarily complicated lambdas:

(lambda (foo bar &optional quux &rest more-stuff)
  (and foo bar (append quux more-stuff)))  ; regular lambda
(##and % %2 (append &3 &*))                ; llama

At first, llama's syntax will seem weird, but you soon get used to it.

A llama expands to a lambda, which you can then use. So instead of this:

(mapcar (lambda (num) (+ 2 num)) '(39 40)) => '(41 42)

you could write just this:

(mapcar (##+ 2 %) '(39 40)) => '(41 42)

Yet llamas aren't the only thing that can help us.

Anaphoric macros also get rid of long lambdas

Dash users will of course be familiar with this:

(--map (+ 2 it) '(39 40)) => '(41 42)

This is an anaphoric macro. Here, it replaces the lambda with a form, which is much shorter. The lambda would take a single argument, which here is bound to the variable it. Anaphoric macros are then another way to make code much shorter when lambdas are involved.

You could then ask: with anaphorics, who needs llama?

But you could also ask: with llama, who needs anaphorics?

This in turn makes us ask:

  • Are they equally good options?
  • Why would you choose one instead of the other?

The answers to these questions are not nearly as straightforward as they might seem. To tackle them, we should first get a better feeling of both llamas and anaphorics in practice.

There's often an anaphoric alternative

Dash is by far the top provider of anaphoric macros for Emacs Lisp, not only in popularity but also in abundance, as it defines more than five dozen of them.

So let's see some examples side by side: the long lambda, the llama, the anaphoric.

The most common cases

It seems that a good two thirds of llamas found in the wild are fed into either mapcar or mapc. So let's look at those first.

mapcar
(mapcar (lambda (x) (upcase (symbol-name x))) '(foo bar)) => '("FOO" "BAR") ; lambda
(mapcar (##upcase (symbol-name %)) '(foo bar))            => '("FOO" "BAR") ; llama
(--map (upcase (symbol-name it)) '(foo bar))              => '("FOO" "BAR") ; dash's anaphoric
  • The first one is your regular long lambda.
  • The second replaces it with a llama.
  • The third is dash's anaphoric.

Here, then, using either a llama or dash's --map can shorten it by some dozen characters.

mapc
(mapc (lambda (x) (push x results)) '(foo bar))  ; lambda
(dolist (x '(foo bar)) (push x results))         ; dolist (uses forms)
(--each '(foo bar) (push it results))            ; dash's anaphoric
(mapc (##push % results) '(foo bar))             ; llama

Here, using llama gives us the shortest, but using just dolist is already quite an improvement.

Other simple, common enough cases

A few other functions from native libraries require a lambda and are common enough. Let's see three of them.

mapcan
(mapcan (lambda (x) (when (natnump x) (list x))) '(x 4 y -3 z w 2)) => '(4 2) ; lambda
(--mapcat (when (natnump it) (list it)) '(x 4 y -3 z w 2))          => '(4 2) ; dash's anaphoric
(mapcan (##when (natnump %) (list %)) '(x 4 y -3 z w 2))            => '(4 2) ; llama

Using llama or dash's anaphoric would shorten this regular mapcan by at least nine characters.

seq-find
(seq-find (lambda (x) (= 0 (% x 3))) '(1 2 4 5 6 7)) => 6  ; lambda
(seq-find (##= 0 (% % 3)) '(1 2 4 5 6 7))            => 6  ; llama
;;                ^ ^ a bit confusing
(--find (= 0 (% it 3)) '(1 2 4 5 6 7))               => 6  ; dash's anaphoric

Here, using llama shortens this seq-find by 11 characters, and dash's --find would remove three more.

The fluctuating difference in length between native+llama versus pure dash's anaphoric boils down to three factors:

  • The difference in length between the native function (here seq-find) and the anaphoric (here --find).
  • The number of times the argument is called, because their names differ in length (e.g. it vs. %).
  • Whether ##fun, ## fun, or llama fun is used. All three are accepted, and the first is recommended.
maphash

So maphash also needs a lambda, which takes two arguments.

;;; lambda
(let ((sum 0))
  (maphash (lambda (_k v) (setq sum (+ sum v)))
           #s(hash-table data (:x 13 :y 14 :z 15)))
  sum)
=> 42

Naturally, llama can replace that lambda.

;;; llama
(let ((sum 0))
  (maphash (##setq sum (+ sum %2))
           #s(hash-table data (:x 13 :y 14 :z 15)))
  sum)
=> 42

Dash, being mostly about lists, has no anaphoric macro to replace maphash.

But hash tables are just xht's thing, and its anaphoric h--each can do the job here:

;;; xht's anaphoric
(let ((sum 0))
  (h--each (h* :x 13 :y 14 :z 15)
    (setq sum (+ sum value)))
  sum)
=> 42

Yet not all anaphorics are about lambdas

As a side note, not all anaphoric macros are a replacement for lambdas — so llamas cannot be an alternative to these.

Two notable examples are dash's anaphoric threading macros --> and -some-->:

(--> 12 (+ 2 it) (mod it 5)) => 4
(-some--> '(foo 4 2 bar)
  (-remove #'symbolp it)
  (-remove #'numberp it)
  (* it it it 10)
  (/ it 7))
=> nil

Sometimes there's no anaphoric alternative

In this case, it would seem as if llama is the only option to get rid of these long lambdas.

But not so fast.

Sometimes dash has non-anaphoric options to avoid long lambdas

dash's -lambda

It seems that -lambda could also be a "competitor" of llama in some cases where it can be used.

But that would depend on what sort of destructuring is being done.

(mapcar (lambda (x) `(,(car x) ,(cdr x))) '((:a . 1)(:b . 2)))     => '((:a 1) (:b 2))  ; lambda
(mapcar (-lambda ((a . d)) `(,a ,d)) '((:a . 1) (:b . 2)))         => '((:a 1) (:b 2))  ; -lambda
(mapcar (##list (car %) (cdr %)) '((:a . 1)(:b . 2)))              => '((:a 1) (:b 2))  ; llama

Above, llama and -lambda have similar readability, but llama wins in size.

And if you're wondering, pcase-lambda would not help much here:

(mapcar (pcase-lambda (`(,a . ,d)) `(,a ,d)) '((:a . 1) (:b . 2))) => '((:a 1) (:b 2))  ; pcase-lambda

That's both because pcase-lambda is a lengthy name, and because its destructuring syntax is noisier than -lambda's.

dash's function combinators

Besides anaphorics, there's another class of "competitors" that llamas must contend with: dash's "function combinators". Though much less well-known than dash's anaphorics, these functions can also get you around regular lambdas, and the resulting expressions are often very readable.

The examples below are sorted by decreasing length, and llamas seem to be slightly longer in most (but not all) of these cases.

-on + -compose

Sometimes sorting destructively is desired, and cl-sort can do that, while also offering a sorting key — a lambda.

;;; lambda
(cl-sort '(("5" . "0") ("1" . "2") ("3" . "9"))
         #'< :key (lambda (x) (string-to-number (car x))))
=> '(("1" . "2")
     ("3" . "9")
     ("5" . "0"))
;;; llama
(cl-sort '(("5" . "0") ("1" . "2") ("3" . "9"))
         #'< :key (##string-to-number (car %)))
=> '(("1" . "2")
     ("3" . "9")
     ("5" . "0"))

The same could also be accomplished with (non-anaphoric) dash instead of llama. Here we use -compose:

;;; dash
;;;; -compose
(cl-sort '(("5" . "0") ("1" . "2") ("3" . "9"))
         #'< :key (-compose #'string-to-number #'car))

Often, non-destructiveness is preferred. For that, there's a dash-only (cl-free) non-anaphoric solution:

;;; dash
;;;; -on + -compose
(-sort (-on #'< (-compose #'string-to-number #'car))
       '(("5" . "0") ("1" . "2") ("3" . "9")))
=> '(("1" . "2")
     ("3" . "9")
     ("5" . "0"))
Side-note: threading

Note that -sort puts the list as last argument, so it has the additional advantage of being suitable for threading-last (if that's your sort of thing), so you could go on modifying the results. For example:

(->> '(("5" . "0") ("1" . "2") ("3" . "9"))
     (-sort (-on #'< (-compose #'string-to-number #'car)))
     (-map #'-value-to-list)
     -flatten  string-join  string-to-number)
=> 123950

Or more efficiently:

(->> '(("5" . "0") ("1" . "2") ("3" . "9"))
     (-sort (-on #'< (-compose #'string-to-number #'car)))
     (mapc (-lambda ((a . d)) (princ (concat a d))))
     with-output-to-string  string-to-number)
=> 123950

Though if that result is what we wanted all along, we could get there faster and simpler with:

(->> '(("5" . "0") ("1" . "2") ("3" . "9"))
     (-map (-lambda ((a . d)) (concat a d)))
     (-sort #'string<)  string-join  string-to-number)
=> 123950

Okay, back to dash's combinators.

-partial

When applying-partially, dash is the shortest.

(funcall (lambda (&rest _) (apply #'+ 13 14 _)) 15) => 42  ; lambda
(funcall (apply-partially #'+ 13 14) 15)            => 42  ; subr.el
(funcall (##apply #'+ 13 14 &*) 15)                 => 42  ; llama
(funcall (-partial #'+ 13 14) 15)                   => 42  ; dash's compiled-fun

Note that combinators produce compiled functions:

(type-of (-partial #'+ 13 14)) => 'compiled-function
-const

Sometimes we want a lambda to return a constant value.

But what to use instead of the lambda depends on what that value is.

A nil:

(mapcar (lambda (&rest _) nil) '(1 nil 3)) => '(nil nil nil)  ; native + lambda
(mapcar (##prog1 nil &*) '(1 nil 3))       => '(nil nil nil)  ; native + llama
(mapcar (##ignore &*) '(1 nil 3))          => '(nil nil nil)  ; native + llama
(-map (-const nil) '(1 nil 3))             => '(nil nil nil)  ; dash + compiled-fun
(mapcar #'ignore '(1 nil 3))               => '(nil nil nil)  ; native + symbol-fun
(-map #'ignore '(1 nil 3))                 => '(nil nil nil)  ; dash + symbol-fun
(--map nil '(1 nil 3))                     => '(nil nil nil)  ; dash + form (anaphoric)

A t:

;; Note: #'always was introduced in Emacs 28.1
(mapcar (lambda (&rest _) t) '(1 nil 3)) => '(t t t)  ; native + lambda
(mapcar (##prog1 t &*) '(1 nil 3))       => '(t t t)  ; native + llama
(mapcar (##always &*) '(1 nil 3))        => '(t t t)  ; native + llama
(mapcar #'always '(1 nil 3))             => '(t t t)  ; native + symbol-fun
(-map (-const t) '(1 nil 3))             => '(t t t)  ; dash + compiled-fun
(-map #'always '(1 nil 3))               => '(t t t)  ; dash + symbol-fun
(--map t '(1 nil 3))                     => '(t t t)  ; dash + form (anaphoric)

A string:

(mapcar (lambda (_x) "foo") '(1 nil 3)) => '("foo" "foo" "foo")  ; native + lambda
(mapcar (##prog1 "foo" %) '(1 nil 3))   => '("foo" "foo" "foo")  ; native + llama
(mapcar (##prog2 % "foo") '(1 nil 3))   => '("foo" "foo" "foo")  ; native + llama
(-map (-const "foo") '(1 nil 3))        => '("foo" "foo" "foo")  ; dash + compiled-fun
(--map "foo" '(1 nil 3))                => '("foo" "foo" "foo")  ; dash + form (anaphoric)

A number:

(funcall (lambda (&rest _) 42) 1 2 "foo" 3) => 42  ; lambda
(funcall (##prog1 42 &*) 1 2 "foo" 3)       => 42  ; llama
(funcall (##+ 42 _&*) 1 2 "foo" 3)          => 42  ; llama
(funcall (-const 42) 1 2 "foo" 3)           => 42  ; dash's compiled-fun
(mapcar (lambda (_x) 42) '(1 nil 3)) => '(42 42 42)  ; native + lambda
(mapcar (##prog1 42 %) '(1 nil 3))   => '(42 42 42)  ; native + llama
(mapcar (##prog2 % 42) '(1 nil 3))   => '(42 42 42)  ; native + llama
(mapcar (##+ 42 _%) '(1 nil 3))      => '(42 42 42)  ; native + llama
(-map (-const 42) '(1 nil 3))        => '(42 42 42)  ; dash + compiled-fun
(--map 42 '(1 nil 3))                => '(42 42 42)  ; dash + form (anaphoric)

When the function is mapcar, the anaphoric --map can be used, and this will be by far the shortest solution.

Otherwise -const will be the shortest one.

-flip

Though restricted to a few cases, -flip can get rid of lambdas:

(funcall (lambda (x y) (- y x)) 3 7) => 4  ; lambda
(funcall (##- %2 %1) 3 7)            => 4  ; llama
(funcall (-flip #'-) 3 7)            => 4  ; dash's compiled-fun

The lambda above could also be rewritten like this:

(funcall (lambda (x y) (- (- x y))) 3 7) => 4  ; lambda
(funcall (-compose #'- #'-) 3 7)         => 4  ; dash's compiled-fun
(funcall (##- (- %1 %2)) 3 7)            => 4  ; llama

so that we could use -compose instead — though that would be longer, as would the llama.

-not

When not shows up in the beginning of a lambda, that's a good candidate for replacing the lambda with dash's -not:

(funcall (lambda (x) (not (keywordp x))) 42) => t  ; lambda
(funcall (##not (keywordp %)) 42)            => t  ; llama
(funcall (-not #'keywordp) 42)               => t  ; dash's compiled-fun
-orfn

When or shows up in the beginning of a lambda, that's a good candidate for replacing the lambda with dash's -orfn:

(seq-filter (lambda (x) (or (stringp x) (keywordp x))) '(:a 1 'b "42" :c)) ; seq  + lambda
(seq-filter (##or (stringp %) (keywordp %)) '(:a 1 'b "42" :c))            ; seq  + llama
(--filter (or (stringp it) (keywordp it)) '(:a 1 'b "42" :c))              ; dash + form (anaphoric)
(-filter (-orfn #'stringp #'keywordp) '(:a 1 'b "42" :c))                  ; dash + compiled-fun

=> '(:a "42" :c)
-andfn

When and shows up in the beginning of a lambda, that's a good candidate for replacing the lambda with dash's -andfn:

With mapcar:

(mapcar (lambda (x) (and (symbolp x) (symbol-name x))) '(foo 3 4 bar))  ; native + lambda
(mapcar (##and (symbolp %) (symbol-name %)) '(foo 3 4 bar))             ; native + llama
(--map (and (symbolp it) (symbol-name it)) '(foo 3 4 bar))              ; dash + form (anaphoric)
(-map (-andfn #'symbolp #'symbol-name) '(foo 3 4 bar))                  ; dash + compiled-fun

=> '("foo" nil nil "bar")

With seq-filter:

(seq-filter (lambda (x) (and (numberp x) (> x 1))) '(4 -1 p 2 z)) => '(4 2) ; seq  + lambda
(-filter (-andfn #'numberp (-cut > <> 1)) '(4 -1 p 2 z))          => '(4 2) ; dash + compiled-fun
(seq-filter (##and (numberp %) (> % 1)) '(4 -1 p 2 z))            => '(4 2) ; seq  + llama
(--filter (and (numberp it) (> it 1)) '(4 -1 p 2 z))              => '(4 2) ; dash + form (anaphoric)

Let's have a look at the types here.

;;;; Types
(type-of (-andfn #'numberp (-cut > <> 1))) => 'compiled-function
(type-of #'numberp) => 'symbol

;; All of these are lambdas:
(type-of (lambda (x) (> x 1))) => 'cons
(type-of (-cut > <> 1))        => 'cons
(type-of (##> % 1))            => 'cons
-cut

The goal of Dash's -cut is close to llama's.

Have a look at this example:

(seq-filter (lambda (x) (> x 1)) '(4 0 -1 2 1)) => '(4 2)  ; seq  + lambda
(-filter (-cut > <> 1) '(4 0 -1 2 1))           => '(4 2)  ; dash + -cut
(seq-filter (##> % 1) '(4 0 -1 2 1))            => '(4 2)  ; seq  + llama

And -cut has no need for a funcall here:

(mapcar (lambda (x) (funcall x 13 14 15)) '(* +)) => '(2730 42)  ; lambda
(mapcar (##funcall % 13 14 15) '(* +))            => '(2730 42)  ; llama
(--map (funcall it 13 14 15) '(* +))              => '(2730 42)  ; dash (anaphoric)
(-map (-cut <> 13 14 15) '(* +))                  => '(2730 42)  ; dash + -cut

The solution offered by -cut is generic enough, so let's give it a better look.

-cut: length

When it comes to length:

  • "-cut " is longer than "##"
  • "<>" is longer than "%" (but same as "%2", "&3", etc)
  • -cut is shorter when %1 is the very function to be replaced, for which llama would need a funcall
-cut: more examples
(funcall (lambda (x y z) (vector t t t x t y z)) nil nil t) => [t t t nil t nil t]  ; lambda
(funcall (-cut vector t t t <> t <> <>) nil nil t)          => [t t t nil t nil t]  ; -cut
(funcall (##vector t t t %1 t %2 %3) nil nil t)             => [t t t nil t nil t]  ; llama
(mapcar (lambda (x) (funcall x -4)) `(abs ,(lambda (x) (+ x 6)))) => '(4 2)  ; native + 2 lambdas
(mapcar (##funcall % -4) `(abs ,(##+ % 6)))                       => '(4 2)  ; native + 2 llamas
(-map (-cut <> -4) `(abs ,(-cut + <> 6)))                         => '(4 2)  ; dash   + 2 -cuts

So it's not much of a stretch to say that dash already has a llama-like solution for "simple lambdas with well-ordered arguments".

-cut: limitations

Unfortunately, -cut has limitations in flexibility:

-cut apparently cannot as in
(directly) put args in sublists (##1+ (car %))
deal with args in different order (##- %3 %2 %5)
repeat args (##+ % %)

Let's look at these "repeat arguments" case:

(mapconcat (lambda (a) (concat a a)) '("x" "y") " ") => "xx yy"
(mapconcat (##concat % %) '("x" "y") " ")            => "xx yy"

Here it seems it has to be a llama: dash will simply... not -cut it.

Another limitation is that the <> of -cut expects arguments in their direct order. We can't change the order.

Still another limitation is that arguments must be at the same level of the function being called, so sublists don't work. But we could get around this one with some creativity. If we look at that cl-sort again, we can now see at least six options (of which llama happens to be the shortest):

;; All of the below evaluate to:
=> '(("1" . "2") ("3" . "9") ("5" . "0"))
;;; regular lambda
(cl-sort '(("5" . "0") ("1" . "2") ("3" . "9"))
         #'< :key (lambda (pair) (string-to-number (car pair))))
;;; pcase-lambda
(cl-sort '(("5" . "0") ("1" . "2") ("3" . "9"))
         #'< :key (pcase-lambda (`(,a . ,d)) (string-to-number a)))
;;; llama
(cl-sort '(("5" . "0") ("1" . "2") ("3" . "9"))
         #'< :key (##string-to-number (car %)))
;;; non-anaphoric dash
;;;; -lambda
(cl-sort '(("5" . "0") ("1" . "2") ("3" . "9"))
         #'< :key (-lambda ((a . d)) (string-to-number a)))
;;;; -compose
(cl-sort '(("5" . "0") ("1" . "2") ("3" . "9"))
         #'< :key (-compose #'string-to-number #'car))
;;;; -cut
(cl-sort '(("5" . "0") ("1" . "2") ("3" . "9"))
         #'< :key (-cut -> <> car string-to-number))
;;             we thread ^ to bring the arg up for -cut

However:

;;;; -cut (doesn't work!)
(cl-sort '(("5" . "0") ("1" . "2") ("3" . "9"))
         #'< :key (-cut string-to-number (car <>)))
;;             because here it's in a sublist ^
!!> wrong-number-of-arguments

But dash can't always save you from long lambdas

Sometimes dash won't have an anaphoric, and -cut won't cut it.

mapatoms

Say we want to know how many primitives our Emacs has.

;;; lambda
(let (prims)
  (mapatoms (lambda (symbol)
              (and (functionp symbol)
                   (subr-primitive-p (symbol-function symbol))
                   (push symbol prims))))
  (length prims))
;;; llama
(let (prims)
  (mapatoms (##and (functionp %)
                   (subr-primitive-p (symbol-function %))
                   (push % prims)))
  (length prims))

There's no dash anaphoric to deal with mapatoms, and -cut won't work here.

mapconcat

Same problem.

Here llama looks better, because dash's solution is too long a workaround.

;;; lambda
(mapconcat (lambda (x) (format "%s (%s)" x (length x)))
           '("hi" "world") ", ")
=> "hi (2), world (5)"
;;; llama
(mapconcat (##format "%s (%s)" % (length %))
           '("hi" "world") ", ")
=> "hi (2), world (5)"
;;; dash
(--tree-mapreduce (format "%s (%s)" it (length it))
                  (concat it ", " acc)
                  '("hi" "world"))
=> "hi (2), world (5)"

Curiously, dash doesn't have a mapconcat equivalent, neither regular nor anaphoric. If it did, the anaphoric would look like this:

;;;; dash doesn't have this one (yet?)
(--mapconcat (format "%s (%s)" it (length it))
             ", " '("hi" "world"))

It would replace the lambda with a form and switch the order, making the list suitable for threading last (with ->>).

And dash might not be available

Finally, maybe you just won't use dash.

Maybe you don't like dash. Or maybe you intend to upstream your code to Emacs, and are avoiding dash as a dependency because, alas, it isn't native. In those cases, dash's functions would of course not be an option. Nor would xht's, since it requires dash.

Should you then choose llama?

The attractiveness of llama depends on a few factors

Let's compare it with its alternatives.

llama vs. anaphorics

Whether llama is a good alternative to anaphorics will depend on factors such as:

  • Whether a library with anaphorics (notably dash) is already being required
  • Whether a library with anaphorics (notably dash) could be required (if not yet) with little cost
  • Whether an exact anaphoric option would exist for the lambda to be replaced
  • Whether llama itself could be required with little cost
  • The arity of the lambda to be replaced
  • Personal preference

llama vs. function combinators

Dash's function combinators can sometimes solve your problem better than an anaphoric would.

Whether to use them instead of llama may depend on:

  • Whether you're already requiring dash
  • Whether you're already requiring llama
  • Whether the cost of additionally requiring one of them would be low
  • Whether you're comfortable with dash's function combinators
  • Questions of size and readability, which will vary from case to case
  • Questions of flexibility, because combinators can't always solve the lambda you want

It's a bit of a mixed bag.

llama vs. regular long lambdas

When dash is not an option, should you use llama to shorten your lambdas?

How compelling this option is might depend on the lambdas you're faced with.

complex lambdas

It's an inherent limitation of llama that it obscures the nature of the input arguments that it defines. This is by design, a seemingly unavoidable side-effect of it being able to create and pass arguments (%, %2, &3, &* …) on the fly.

In our opening example we had this:

(lambda (foo bar &optional quux &rest more-stuff)
  (and foo bar (append quux more-stuff)))  ; regular lambda
(##and % %2 (append &3 &*))                ; llama

But looking just at the llama gives you little idea of what that &3 stands for.

Although llama makes it much more compact, the long lambda gives you a much better hint of what it is you'll be passing to it (we need a foo and a bar; a quux may be useful as well; and more-stuff, if that's available).

So what llama gives you here in convenience and shortness, it takes away in readability: the longer the lambda, the less clear the nature of the input it expects to receive.

How to deal with this will depend on the situation.

  • If you needed to call one such lambda repeatedly, you could for example use llamas, and add a comment near them about the variables involved.
  • If however you need to call it once, and the context doesn't help, you might as well go with the regular lambda.

The point here is that even if you could use llama to replace a lambda like this one, you may prefer not to because it would obscure the nature of the arguments.

simple lambdas

At the other end of the spectrum, we have very simple monadic lambdas that are passed to functions whose nature of the input is clear to you, or at least easy to infer. In those cases, llama has much improved readability.

That's good news. Of the lambdas required by functions, most are monadic. And mapcar and mapc are ubiquitous.

This means that the greatest part of the explicit long lambdas that you're likely to meet while coding can be shortened by llamas with little to no cost in readability. They're things such as this:

;; from simple.el
(defun minibuffer-default-add-shell-commands ()
  ...
  (setq commands (mapcar (lambda (command)
                           (concat command " " filename))
                         commands))
  ...)

which llama would turn into just this:

(defun minibuffer-default-add-shell-commands ()
  ...
  (setq commands (mapcar (##concat % " " filename)
                         commands))
  ...)

You, being used to mapcar, and faced with the variable commands, which you know must be a list, will then quickly see that the % refers to a command.

Therefore, if you are a dash-averse person who would nevertheless like to see your long lambdas gone, then llama should be an attractive option to you.

See next

Here we looked at the case where you are still unsure whether to pick llama or pick a library full of anaphorics.

Now suppose you have already decided that you'll be using one such library. Should you then use its anaphorics? Or should you use their non-anaphoric counterparts plus a llama?

We give this question a closer look in Part II.