Skip to content

Blog

Magic isn't clever - it's emergent: relational programming for imperative programmers

If you come from the imperative world, you are probably sceptical about the premise of this library. Saying what is true about the result and expecting the engine to work it out sounds like intelligence, and these days we associate intelligence with LLMs, which take warehouses of GPUs to run. But logic programming — relational programming, if you prefer the name that stresses what it works on — is much older, and used to run on hardware that your backend server puts to shame. There is nothing clever in the engine. It is closer to a Sudoku solver than to a chatbot: your rules define a space of possible answers, and it walks that space methodically — try, record, undo, try the next — and hands back everything that holds. Unlike a chess engine, it isn't looking for the best answer; it's looking for all of them. A search space for chess is enormous and a lot of engineering goes into compressing it. The invoices and shipment legs you write are much simpler, so a small library can manage. This article is an outline of how it does that — how your declarations become a search — and stops before the question of how it knows when the search is done, which deserves its own.

The half of the Tar Pit we skipped

Programming is irreducibly difficult. Fred Brooks diagnosed it as such four decades ago in "No Silver Bullet," and told us how the difficulty could be addressed. Two decades later, Mosley and Marks took up the same question in "Out of the Tar Pit," this time by surveying the tools we use and how they make our lives harder. Despite this long lineage of deliberation, mainstream languages still offer the approaches we had forty years ago. Programming is as expensive, stressful and unreliable as it was then. Why? Aren't the incentives good enough?