Top
Best
New

Posted by azhenley 1/16/2026

My Gripes with Prolog(buttondown.com)
140 points | 87 commentspage 2
floxy 1/16/2026|
I guess we are supposed to pile on, so I'll add that the author should read "The Art of Prolog" (Sterling & Shapiro) and then "The Craft of Prolog" (O'Keefe).
YeGoblynQueenne 1/16/2026|
And also "Prolog Programming for AI" by Bratko and "Programming in Prolog" by Clocksin and Mellish.

Although these days I'd recommend anyone interested in Prolog starts in at the deep end with "Foundations of Logic Programming" by George W. Lloyd, because I've learned the hard way that teaching Prolog as a mere programming language, without explaining the whole logic programming thing, fails.

egl2020 1/16/2026||
Maybe it's just me, but my gripe is that it looks declarative, but you have to read the code in execution order.
bw86 1/16/2026||
findall instead of bagof can also help for these cases.

    | ?- findall(A, (tree(A, N), branch(N)), As).

    As = [n,n1]

    yes
See https://lpn.swi-prolog.org/lpnpage.php?pagetype=html&pageid=...
subjectsigma 1/16/2026||
Re: the comma-at-end-of-line thing: I would sometimes write Prolog like so to avoid that issue:

    goal :-
        true
        , subgoal(A, B)
        , subgoal(B, C)
        .        
This is definitely not standard and I don't know if the WAM optimizes out the gratuitous choice point, but it certainly makes the code easier to work with.
YeGoblynQueenne 1/16/2026||
It's not standard but that's how I write Prolog. I thing I got it from SQL?

I don't usually leave the full-stop on its own line though. You can always select the entire line, then move one down to cut it without catching the full stop. If that makes sense?

cyberpunk 1/16/2026||
I actually like , ; . in erlang. Maybe I’m an alien.
Joel_Mckay 1/16/2026||
"Depends how you felt about Elixir" |> String.graphemes() |> Enum.frequencies()

Best regards =3

doorhammer 1/16/2026||
I always come back to prolog to tool around with it but haven’t done a ton.

Bidirectionality has always been super fascinating.

Didn’t know about Picat. 100% going to check it out.

hwayne 1/16/2026|
I'll warn you that Picat is very much a "research language" and a lot of the affordances you'd expect with a polished PL just aren't there yet. There's also this really great "field notes" repo from another person who learned it: https://github.com/dsagman/picat
doorhammer 1/16/2026|||
Side note: Just clocked your name. Read through Practical TLA+ recently modeling a few things at work. Incredibly helpful book for working through my first concrete model in practice.
doorhammer 1/16/2026|||
Totally fair. Realistically “check it out” means I’ll probably spin up an env and try modeling a few things to see how it feels.

I’m mostly a language tourist they likes kicking the tires on modes of modeling problems that feel different to my brain.

Started skimming those notes. Really solid info. Appreciate it!

ristos 1/16/2026||
No functions:

You can't do length + 1 as a single expression in any language though, in python for example len(ls) + 1 is two expressions, but I get what you mean, it is a little less terse. But those commas in prolog are super useful. And you can make your example bidirectional too:

``` :- use_module(library(clpfd)).

foo(List, X) :- length(List, Out), X #= Out + 1. ```

``` ?- foo(X, 3). X = [_, _] .

?- foo(X, 3), X = [a,b]. X = [a, b] . ```

-----

No standarized collection types:

I think that's a feature rather than a bug. The ability to just use infix and compound terms in a generic way without it being tied to a clause or operator is a huge feature. For example:

``` pets(dog-rex-poodle, dog-fluffy-bishon). ```

That defines the collection in a semantic or mathematical sort of way, then you can pass that into whatever data structure you want, whether it's a ordered map or a hashmap or whatever.

----

No boolean values:

That's also a feature in prolog, same as having no null. It's the same sort of motivation for Haskell's Maybe and Either types or Rust's Option and Result types, same kind of usefulness.

----

Cuts are confusing:

Conditionals don't need to use cuts, the modern prolog way of doing it is using the reif library:

``` :- use_module(library(reif)).

if_(Cond, Then, Else) ```

For example:

``` :- use_module(library(clpfd)). :- use_module(library(reif)).

sign(X, S) :- if_(X #> 0, S = pos, S = nonpos). ```

---

Non-cuts are confusing:

This isn't doing what you're thinking:

``` \+ (A = B) ```

It's unifying A with B, `A = B` unifies. You want `dif(A, B)`.

----

Straying outside of default queries is confusing:

It might be tempting to use bagof, but it's not monotonic. You should try to write as much prolog code as you can in a pure, monotonic way, so your code can take advantage of prolog's unique advantages, like monotonic debugging.

Check out the SWI prolog discourse group, there's a lot of good stuff in there and everyone's very supportive to newbies. And Markus Triska's website and youtube channel Power of Prolog is a super useful resource for all this stuff, a good place to go if you want to know what sets prolog apart. A lot of prolog's usefulness doesn't show up as an embedded language either, like minikanren isn't "pretty much prolog", it lacks a lot of stuff that prolog offers. Multiparadigm programming languages are also really popular now, but a lot of what sets programming languages apart isn't what they can do, it's what they can't do, what sort of paradigm or way of thinking they force you to adopt.

victorbjorklund 1/16/2026|
You can do it in one expression in Elixir:

x = length(list) + 1

On the other hand I don’t really see why it is an issue with Prolog (maybe there are more complicated situations than the example)

YeGoblynQueenne 1/16/2026||
It's not an issue. "+" is not a function in Prolog. So, for example, X = 1 + 1 means that the term 1 + 1, or +(1,1), is bound to the variable X. It doesn' t mean that 1 + 1 is evaluated, and its result assigned to the variable X. Prolog doesn't have assignment, and all its data structures are immutable, including variables, so once a variable is bound it stays bound for the scope of the current execution branch. That's unification.

The thing to keep in mind is that Prolog borrows its syntax and semantics from (a fragment of) First Order Logic, and that's where its treatment of functions comes from. In FOL there's a concept of a "term": a variable is a term, a constant is a term, and a function symbol followed by one or more comma-separated terms in parentheses is a term. So if f is a function symbol, f(X,a(b), c) is a term, where X is a variable (in Prolog notation where variables start with capital letters or _). Terms are mapped to functions over objects in the domain of discourse by a pre-interpretation (long story). Terms are arguments to atomic formulae which look exactly like terms with one or more arguments, except they have predicate symbols rather than function symbols, so if p is a predicate symbol, then p(f(X,a(b), c), d, 1, 2, 3) is an atomic formula, or atom.

There's a bit of terminological confusion here because Prolog calls everything a "term", including atomic formulae, and it calls its constants "atoms", but, well, you learn to deal with it.

The difference between terms (in both Prolog and FOL) and functions (in most programming languages) is that terms are not evaluated and they are not replaced by their values. Rather, during execution of a Prolog program, variables in a term are bound to values, by unification, and when execution is over, if you've got all your ducks in a row, all variables in your program should be bound to some term with no variables, and all terms be "ground" (i.e. have no variables).

That's because a ground term is essentially a proposition, and so it has a truth value of true or false. The point of FOL and of Prolog, and every other logic programming language is to carry out a proof of a theorem, expressed as a logic program. If a term has variables we can't know its truth value because it may correspond to a different value of a function, depending on the values of its variables. So to know the truth or falsehood of a term we need to ground it. Unification in Prolog is a dirty hack that allows the proof to proceed without fully grounding terms, until the truth of an entire theorem is known, at which point everything becomes ground (or should be ... more or less, it depends).

ASP (Answer Set Programming) instead starts by grounding every term. Then, it basically treats a logic program as a SAT formula and uses a SAT-solver to find its truth or falsehood (it does more than that: it gives you all models of the theorem, i.e. every set of ground atoms that makes it true).

And that's where the tiger got its stripes. Don't expect Prolog (or ASP for that matter) to work like other languages, it has its own semantics. You don't have to like them, but there's a reason why everything is the way it is.

shawn_w 1/16/2026||
I frequently find myself thinking "this would be a great fit for prolog etc." but always fail when it comes to the execution.
mcswell 1/16/2026|
That's easy:

thisWouldBeGreat: !, fail.

fithisux 1/16/2026|
The logic programming space has more than Prolog

Picat (mentioned by the author) Datalog Mercury XSB

are there more?

More comments...