26

I thought I understand how pattern matching like found in Scala and Haskell is different from unification found in Prolog but my misunderstands of Prolog is great. What is some simple problems solvable by one that cannot be solved by the other? Thank you

Eli Schneider
  • 4,717
  • 3
  • 24
  • 50

4 Answers4

31

Simple statement: pattern matching is one-way, unification is two-way. That is, in Prolog the right-hand side (the one being matched against) can include unbound variables. E.g., if you have two unbound variables X and Y, this will work fine:

X = Y,
X = 5,
%% Y = 5 now as well

In Erlang (which uses pattern-matching with syntax close to Prolog), the line X = Y will produce an error: variable 'Y' is unbound. Note that X being unbound is fine: it is supposed to be pattern-matched.

This can be useful when you want to deal with partially-defined values. A very good example is difference lists.

This is also what allows use of Prolog predicate in multiple modes. E.g. in Scala/Haskell/Erlang, if you want to 1) find A ++ B, 2) solve the equation A ++ X == B, or 3) solve the equation X ++ A == B for given lists A and B, you need to write 3 separate functions; in Prolog, all these jobs (and more!) are done by one predicate.

Alexey Romanov
  • 154,018
  • 31
  • 276
  • 433
  • Exercise your Prolog pattern-matching skills at the SWI Prolog interactive editor [SWISH](http://swish.swi-prolog.org/), use the lower right REPL window. Note that unification is actually about imposing a series of constraints across expression trees (try to run `f(g(X,Y),H) = f(Z,g(a,[L,X,Y])), X=12.`), it may even handle infinite trees. [Unification](http://en.wikipedia.org/wiki/Unification_%28computer_science%29) is an amazingly powerful idea, whole books have been written about this lowly algorithm, in particular about how to optimize it and there is still work to do. – David Tonhofer Nov 29 '14 at 09:10
  • Nonsense. Try to unificate this: `?- B = X + A, B is 3, A is 2.` – Feofilakt Jan 18 '16 at 08:29
  • @Feofilakt, "is" is a one way binding. You need to write terms for peano numbers: 0, s(0), s(s(0)), ... or depending on the problem you might expicityle state succ(zero, one), succ(one, two), ... In either case arithmetic becomes unifiable. – Samuel Danielson Mar 13 '16 at 21:00
  • @Samuel Danielson, I know that arithmetic is unifiable, I just was resented by the Alexey Romanov's answer, that describes only advantages of unification in prolog and hides disadvantages. Explanations like this confuses prolog's beginners who will think that unification always works well (like me in some time). In real tasks unification becomes as powerful as pattern-matching, not more. – Feofilakt Mar 15 '16 at 07:26
  • @Feofilakt Your example doesn't demonstrate any disadvantages of unification compared to pattern matching, because it won't work with PM either. So what _are_ those disadvantages which this answer is hiding? – Alexey Romanov Mar 15 '16 at 09:41
  • @Alexey Romanov Yes, my example doesn't demonstrate disadvantages of unification compared to pattern matching, it demonstrates that unification and pattern matching both have same disadvantages (for arithmetic, by example). That are those ones which answer is hiding. By reading the answer, you can think that PM has those, and unification has not. – Feofilakt Mar 16 '16 at 04:21
  • @Feofilakt The question is about _differences_ between PM and unification, so that's what the answer talks about. "By reading the answer, you can think that PM has those, and unification has not". How? If this were the case, it would be an advantage of unification, and would be mentioned in the answer, but it isn't. – Alexey Romanov Mar 16 '16 at 10:31
  • @Feofilakt Finally, as you say you know arithmetic is unifiable, this is a disadvantage of arithmetic in Prolog rather than unification. There certainly _are_ many tasks where advantages of unification are irrelevant, but Prolog is (usually?) just not the right tool for them. – Alexey Romanov Mar 16 '16 at 10:46
  • @Alexey Romanov You gave an example and I just wrote counterexample (sorry for some roughness). All what we need is to change X ++ A == B for X + A = B. I assure you, beginner will be surprised that taking numbers instead of lists will crash all beauty. "this is a disadvantage of arithmetic in Prolog rather than unification" - no, that is disadvantage of Prolog itself. – Feofilakt Mar 17 '16 at 03:22
  • @Feofilakt Not a problem: `?- 8 #= X + 3.` => `X = 5.` in modern Prolog (since 20 years or so). Read all about it: https://www.metalevel.at/prolog/clpfd – Felixyz Aug 21 '17 at 22:55
  • @Felixyz And what about performance? Such tricks had been discussed at swi-prolog group and much slowdown was showed there – Feofilakt Aug 22 '17 at 10:29
8

I think it is useful to formalize the concepts, instead of looking into a specific language. Matching and unification are fundamental concepts that are used in more contexts than pattern matching and prolog.

  • A term s matches t, iff there is a substitution phi such that phi(s) = t
  • A term s unifies with a term t, iff there is a substitution such that phi(s) = phi(t)

To give an example we inspect the terms s = f(Y,a) and t = f(a,X) where X,Y are variables and a is a constant. s does not match t, because we cannot universally quantify the constant a. However, there is a unifier for s and t: phi = {X\a, Y\a}

hexhex
  • 123
  • 2
  • 5
1

In Prolog, you can append [3] to [1,2] like this:

?- append([1,2], [3], Z).
Z = [1, 2, 3].

The neat thing about unification is that you can use the same code (the internal definition of 'append'), but instead find the second argument needed to get the result from the first argument:

?- append([1,2], Y, [1,2,3]).
Y = [3].

Rather than coding by writing "do this, then do that", you code in Prolog by saying what you know. Prolog treats the facts you give it as equations. Unification lets it take those equations and solve for whatever variables you don't yet know the values of, whether they're on the right or left side.

So, for instance, you can write a planner in Prolog, and you can run it "forward", giving it a plan and having it predict its results; or you can run it "backward", giving it a set of results and having it construct a plan. You could even run it both ways at once (if you were careful in your coding), specifying a set of goals and a set of constraints on the plan, so that you could say "Find a plan for getting to work that does not involve taking the subway."

Phil Goetz
  • 484
  • 4
  • 14
1

The following in Scala would fail to compile, as it's first case branch attempts to declare the variable x twice.

(1, 1) match{
   case (x, x) => println("equals")
   case _      => println("not equals")
}

If Scala used unification instead of pattern matching this would succeed and print "equals" while

(1, 2) match{
   case (x, x) => println("equals")
   case _      => println("not equals")
}

would print "not equals". This is because the unification would fail when attempting to bind the variable x to both 1 and 2.

Dave Griffith
  • 20,025
  • 3
  • 51
  • 74
  • 10
    Actually, this is the difference between linear (as in Scala and Haskell) and non-linear (as in Erlang and Mathematica) pattern matching. – Alexey Romanov Dec 14 '10 at 18:14