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
cl-destructuring-bind has a very lightweight syntax.
-let is also lightweight, and has a definite Clojure
pcase uses a backquote syntax that’s familiar if you’ve
written macros, and shadchen’s
match uses patterns based
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
-let here, as
they require a single matching pattern.
match take different attitudes to a failing pattern
match. If we pass in
(list 1 2 3) to the code above,
match signals an error. If we want to ignore
other cases with
match, we have to handle it explicitly:
A full-featured pattern matching library should include the ability to skip elements, so naturally this is possible too:
match explicitly use
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:
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:
If you have an explicit cons pair, it may not be a proper list. You can match on this instead:
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:
Shadchen is very powerful, and even allows recursing with
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
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,
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.