Comment by nubela
15 years ago
Perhaps it is just me, but does anyone else think Prolog is really just a nicely done language that revolves around the an if-then-else condition? Its basically pattern matching... But consider me troll and argue your stand.
No, it's unification and backtracking.
Unification is far more powerful than pattern matching, which (among other things) supports working with partial information - you can pass around a list of cons cells where the cdr is an unbound variable, and then bind it to another cons cell with an unbound cdr to get O(1) appending, for example. (These are called difference lists.) Same can be done with trees and other, more complex data structures. In effect, rather than fully immutable or fully mutable variables, you get variables that can only be set once, and then semantically "always were" that value. (but possibly undone on backtracking)
Backtracking means that pattern-matching a variable isn't just pass/fail, but potentially a generator (AKA "iterator", etc.) for all matching values. Sometimes (ok, often) the ensuing combinatorial explosion keeps it from scaling efficiently to real problems, but constraint programming compensates, pruning off a LOT of the space of potential solutions before searching. And, saying, "here's my problem, throw everything at it and figure it out" in very few lines of code is still great for prototyping.
Comparing Prolog to Erlang makes the difference clearest, to me. Erlang doesn't do backtracking (because it throws soft-real-time guarantees out the window!) or full unification (because passing around and subsequently binding unbound variables would be a form of non-local state). Erlang is still a great language IMHO, but it's a very different kind of language, because those two features are what make Prolog Prolog.
Prolog's pattern matching actually isn't much like an if-then-else construct at all, and thinking about it like one will get you into a lot of trouble once you move beyond very very trivial Prolog programs. While it resembles the pattern matching done in Haskell and ML-like languages at first glance, what's actually happening in Prolog is very different.
A look at a simple (although very inefficient) Fibonacci program will illustrate the difference. In Haskell, it'd look something like this: (and work like you might expect)
The obvious direct translation to Prolog (I'm using SWI Prolog[0]) is something like this:
This, however, is going to cause problems if you actually try to run it, and the reason is that Prolog doesn't just do pattern matching: it attempts to unify the query term (the thing you give it) with the program terms (the things on the left in the program above), and instead of just using the first result that matches, it will (if you ask it to do so) return every possible result by doing a left-to-right depth-first search on the solution tree (using a process called SLD resolution[1]). The expected behavior of the above program is something like this:
What's actually going to happen though is this:
When you give it the query fib(0,X), it first unifies that with fib(0,0), and the first answer is what you expect: X = 0. The difference occurs when you ask it for another answer (which you do in the interpreter by typing a semicolon). What you want Prolog to say is that there are no other answers, because there's only one 0th Fibonacci number. What Prolog actually does though is it backtracks[1] and goes back up the resolution tree to see if there are any more program terms the query can be unified with. In this case there are: fib(0,X) can unify with fib(N,X) also. Prolog soon gets into negative numbers (and past the base cases), and so ends up running forever.
One possible corrected version is below:
Here, we ensure that we only unify with the third query when N is large enough that we don't match the first two, and so we get the output we'd expect.
[0] http://www.swi-prolog.org/ [1] http://en.wikipedia.org/wiki/SLD_resolution [2] http://en.wikipedia.org/wiki/Backtracking
For small programs you are probably right.
However, the key of learning Prolog to teach you how to expresses the logic of a program/system without describing its control flow. Basically to describe what the program or system should accomplish (which rules govern the program or system) without thinking how these things will be implemented and executed (it will just happen). This kinda of thinking can be very powerful tool when designing complex systems and products.
it might be just you and a bunch of other people who don't understand prolog.
if statements are not horn clauses. if statements are procedural and specify execution order and don't pattern match.
prolog's execution is resolution, done using unification over logic variables.
as a simple example: member/2
member(X,[X|_]). member(X,[_|T]) :- member(X,T).
if I query: member(1,[1,2,3]) this is true
if I query:
member(X,[1,2,3]), this is true, for X=1, X=2 and X=3
similarly you can ask append([1,2,3],[4,5,6],X) to get X=[1,2,3,4,5,6]. and ask append([1,2,3],X,[1,2,3,4]) to get X=4
for example:
to produce all possible combinatons of items from a series of lists:
comb([],[]) comb([H|T],[X|Y]) :- member(X,H), comb(T,Y).
so if I do
comb([[a,b,c],[d,e,f],[g,h,i]],X) I get X = a,d,g or X = a,d,h and so on and so on
as you might see, it is a little bit more obvious that it isn't just a series of 'if statements' but a series of relations between clauses