Pattern matching is invaluable in elisp. Lists are ubiquitous, and a small amount of pattern matching can often replace a ton of verbose list fiddling.
Since this is Lisp, we have lots of choices! In this post, we’ll compare cl.el, pcase.el, dash.el, and shadchen, so you can choose the best fit for your project. We’ll look at the most common use cases, and end with some recommendations.
For the sake of this post, we’ll consider both pattern matching and destructuring, as they’re closely related concepts.
A Simple List
Let’s get started with a list that always has three elements. All four of our libraries work here:
Already, we can see some major syntactic
differences. cl-destructuring-bind
has a very lightweight syntax.
-let
is also lightweight, and has a definite Clojure
influence. pcase
uses a backquote syntax that’s familiar if you’ve
written macros, and shadchen’s match
uses patterns based
on
Racket’s pattern matcher.
Users often want to use patterns inside let
bindings, so three of
our libraries provide this too. It’s a little paren-heavy, but useful
when you need it.
Lists of Different Lengths
It’s very common to have lists of different lengths, and pattern matching is a great fit here.
We can’t use cl-destructuring-bind
, pcase-let
or -let
here, as
they require a single matching pattern.
pcase
and match
take different attitudes to a failing pattern
match. If we pass in (list 1 2 3)
to the code above, pcase
just
returns nil
whereas match
signals an error. If we want to ignore
other cases with match
, we have to handle it explicitly:
Skipping Elements
A full-featured pattern matching library should include the ability to skip elements, so naturally this is possible too:
pcase
, -let
and match
explicitly use _
for
placeholders. cl-destructuring-bind
doesn’t care and just binds _
like any other variable.
Values in Patterns
Pattern matching can really help when you’re expecting explicit values in certain places.
For literals, it’s straightforward:
If we want symbols, it takes a little more care with our quoting:
Repeated Values
This is sometimes called ‘non-linear patterns’, and is less common in languages with pattern matching built-in (e.g. Haskell doesn’t support it). Since pattern matching is just a macro library, we can pick the library that provides this:
Cons Cells
If you have an explicit cons pair, it may not be a proper list. You can match on this instead:
Where Clauses
Testing values against a predicate isn’t really pattern matching, but it’s a popular feature in languages with built-in pattern matching. We can do this too:
Recommendations
Shadchen is very powerful, and even allows recursing with match-let
or function declaration with defun-match
. However, it’s not
namespaced and the documentation isn’t as good.
dash.el doesn’t let you use multiple patterns, nor can it match on
literal values. The syntax is very readable though and it has
excellent docstrings. You can also use its patterns with the other
dash binding macros, such as -if-let
.
pcase.el has both excellent docstrings and examples in the info manual, which makes up for slightly noisier syntax. It’s also widely used in Emacs core and some popular Emacs packages, such as magit and use-package.
Now we’ve seen some examples, which should you pick? If you’re already
using dash.el in your projects, it’s a no-brainer: use -let
. If not,
give pcase
a try: it’s built-in, it’s used extensively in core, and
it’s the only library that worked in every scenario we looked at.