I was trying to put together a rule engine for a little university project in Java. The result was turning out to be an absolute mess: a maze of nested conditionals, chained if-else statements, and for loops that, by the time I reached line 300, I didn't even know what the hell I was checking anymore.

And then, while rummaging through a folder full of old papers from my Artificial Intelligence class, I stumbled upon my Prolog notes. I hadn't touched it since I passed the subject, but I decided to download the latest version of SWI-Prolog and mess around for a bit. It was like completely switching gears in my brain.

Changing the way you think

Those of us who spend our days writing code in C, C++, or Java are taught to be CPU dictators. We tell the machine exactly how it has to do things step by step: "Create this iteration variable, loop through this array, if the value is greater than X, then increment this counter". That's your standard imperative programming.

Prolog is a radically different beast. It's logical and declarative programming. Instead of giving it meticulous instructions, you describe to the machine what is true, you set the rules of the game, and you let it infer the solution on its own using its internal inference engine (the famous backtracking). Instead of building a detailed algorithm, what you do is build a knowledge base.

To test if I remembered anything, I put together a classic little example. Imagine you want to model family relationships, or access permissions to a complex system. In C, you'd set up your structs, use pointers, linked lists, and recursive functions out the wazoo. In Prolog, you simply declare concrete facts and logical rules.

A look at the code

I opened my favorite editor (Notepad, what did you expect) and wrote this in a sad little rules.pl file:

% Facts: what we know to be strictly true
es_padre(juan, maria).
es_padre(juan, pedro).
es_padre(pedro, ana).
es_madre(laura, maria).

% Rules: how to deduce new information from facts
es_progenitor(X, Y) :- es_padre(X, Y).
es_progenitor(X, Y) :- es_madre(X, Y).

es_abuelo(X, Z) :- es_padre(X, Y), es_progenitor(Y, Z).
es_hermano(X, Y) :- es_progenitor(Z, X), es_progenitor(Z, Y), X \= Y.

You save the file, fire up the interpreter in the console, and start asking it queries. The magic of this is that you don't tell it to search for a piece of data by iterating; you simply ask it if something is true based on its universe:

?- es_abuelo(juan, ana).
Yes

?- es_hermano(maria, pedro).
Yes

?- es_abuelo(X, ana).
X = juan

Boom! Look at that last query. I didn't ask it if Juan is the grandfather, I literally asked it who Ana's grandfather is using a variable (X). The Prolog engine evaluated the rules, cross-referenced the available data in its logical tree, and returned X = juan. And all this without writing a single search loop.

The future (and present) of declarative programming

It's true that Prolog isn't the tool you're going to use to build a dynamic webpage in PHP, nor to make a billing system. Tinkering with it can be very frustrating at first because backtracking sometimes plays tricks on you and gets you into infinite loops if you don't properly handle the cut operator (that damn !).

Even so, I firmly believe that this "tell me what you want and I'll figure out how" approach makes a lot of sense for certain architectures, especially if you get into expert systems, theorem proving, or when you have to handle highly convoluted decision trees. In fact, if you think about it, languages like SQL work under a very similar paradigm: you throw a massive SELECT and the database engine figures out how to optimize the execution plan and fetch the rows for you.

I don't know if in ten years Prolog will experience a renaissance or remain that academic oddity we only see in university classrooms and forget upon leaving, but the idea of separating logic from control still seems brilliant to me. For now, it has saved me from writing another five hundred lines of unreadable code today.