Equals is an Assertion, not an Assignment

One of the most difficult mental shifts when going from imperative to
functional programming comes when reading the ‘=’ operator. At least, I’ve
found this to be true of me. For the benefit of anyone else with the same
problem, I want to present a potentially new and hopefully helpful way of
thinking about “assignment” in functional languages.

First off though, a note on scope: This article is about pattern-matching
functional languages like Elixir, Erlang and Haskell. It is not applicable (as
far as I know) to Lisps.

Here’s a line out of one of my Elixir programs.

Reading this causes immediate problems for the reader who is fresh off an
imperative language. Naively translated to Ruby, it looks like:

…which makes no sense, and doesn’t compile, because you can’t assign
a value to an array.

The reader reads up on pattern-matching, though, and begins to understand
this code a bit better. She realizes it’s kind of like doing regex
pattern-matching in Ruby.

In the Elixir code a successful pattern match results in variables being
bound. We can get a little closer to that in our regular-expression example
using named captures.

This is as far as most explanations of pattern-matching get, in my
experience. But it doesn’t tell the whole story.

Let’s look at an alternative syntax for doing regular expression matches in
Ruby.

This (little-known) form of regex matching causes local variables to be set
as a side effect of the match. (This might not seem quite so strange if you’re
aware that Ruby also sets a bunch of Perl-style automatic variables like
$& , $1, $2, and so on, as a side
effect of a regex match).

This is starting to look a little closer to our original example of a
functional “assignment”. But we’re not there yet. Here’s what I think a
pattern-matching assignment is really equivalent to in Ruby
regex-matching terms:

(I’ve extracted the data to match on into a variable to keep
the lines shorter)

See the addition of the assertion at the end of the matching operation?
That’s the key piece that was missing before.

Because using the ‘=’ operator in a language like Elixir doesn’t just
pattern-match. It asserts that the pattern match will be successful. If
it doesn’t succeed, the code will fail at that point. This is the realization
that I came to about pattern-matching languages: the ‘=’ operator isn’t
assignment. It’s a pattern-matching assertion which may, as a side effect,
bind variables
.

Sometimes the pattern is very simple. A line like this will always
succeed:

That’s because Elixir has a rule that says, in effect, “a pattern consisting
of a bare variable name will match any value”. Oh, and coincidentally it will
also assign that value to the variable name.

In effect, assigning to a bare variable is like matching on a universal
regex:

(Note that other languages handle bare variable names a little differently,
and add the proviso that the variable must previously be un-assigned in order
to match anything.)

So when you see code like this:

You can read it like this: “Try and match the result of
fetch_feed(account) against a pattern consisting of a two-element
tuple, where the first element is the atom :ok, and the second
element can be anything. If the match succeeds, also assign the second element
to the variable name body. If it fails, raise an exception
immediately.”

I hope this helps someone.