Thanks, I don't really know much about Functional Programming. My expertise is in logic programming which btw is a different paradigm. I've heard it said that they're similar and it seems to me the reason was the support for pattern matching in functional languages.

I agree that what "pattern matching" means depends on a programmer's background. It's interesting that the wikipedia article that you link to does not mention "unification" at all and only has one reference in Prolog as one of a group of example languages with a "pattern matching construct"; which is not how I would describe the use of the unification algorithm in Prolog.

To be honest, I am not sure what is meant by "pattern matching". It seems to be a loosely defined term, like "Finite State Machine" (as opposed to "Finite State Automaton"). I expect that the book you linked to has a more formal treating, perhaps, but from what I can tell from a quick look the "pattern matching" here is based on types. In Prolog, unification is used to bind values to logic variables, which do not have types. So a variable, X, in Prolog can unify, i.e. "match with" absolutely anything. A "pattern" then can be formed by constructing terms (the only data structure in Prolog) with "holes" like p(X, a, b, Y,[1,2,3|Tail], f(Z)) etc. where capital letters are variables.

One use of this ability is to manipulate singly-linked lists to insert in or remove elements from their tail, where normally only the head of such a list can be accessed directly. What I mean is that in Prolog a list is denoted by the special syntax [H|T] where H is the head of a list (and can be any term, including another list) and T is the tail of the list, another list.

Normally one appends to a list in Prolog using the append/3 predicate:

append([], L, L).
append([H|T], L, [H|R]) :-
append(T, L, R).

This works on ordinary lists, but it is also possible to define a "difference list" as a term, e.g. like:

[a,b,c,d|T]-T

Where T is a variable bound to the end of the tail of the list. Two difference lists like that one can be appended with the following predicate:

append_dl(Xs-Ys, Ys-Zs, Xs-Zs).

For example:

?- Xs = [a,b,c,d|T1]-T1, Ys = [e,f,g,h|T2]-T2, append_dl(Xs,Ys,Zs).
Xs = [a,b,c,d,e,f,g,h|T2]-[e,f,g,h|T2],
T1 = [e,f,g,h|T2],
Ys = [e,f,g,h|T2]-T2,
Zs = [a,b,c,d,e,f,g,h|T2]-T2.

The result of appending is in Zs, but you can see the result of the intermediary unification steps in the other variables echoed in the Prolog REPL (the "listener").

Of course, because this is Prolog you can also use the same predicate to split a list:

?- Xs = [a,b,c,d|T1]-T1, Zs = [a,b,c,d,e,f,g,h|T2]-T2, append_dl(Xs,Ys,Zs).
Xs = [a,b,c,d,e,f,g,h|T2]-[e,f,g,h|T2],
T1 = [e,f,g,h|T2],
Zs = [a,b,c,d,e,f,g,h|T2]-T2,
Ys = [e,f,g,h|T2]-T2.

Where Ys is what remains if we split Xs from Zs.

Appending or splitting lists like this is preferred to append/3 because it appends the two lists in a single operation so it can be used to economically put a list together in a loop. The same technique is used with Prolog's Definite Clause Grammars where the "difference" in a difference list is the start and end of a string accepted by a grammar, acting as a parser.

https://en.wikipedia.org/wiki/Definite_clause_grammar

Sterling and Shapiro's "The Craft of Prolog" has a nice chapter on "Incomplete Data Structures" using difference lists and patterns with "holes" but I don't think there's a free version online, unfortunately.