# Hillel Wayne: "My Gripes with Prolog"

**URL:** <https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484>\
**Category:** General\
**Tags:** discussion\
**Created:** [January 20, 2026, 11:22pm UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484 "2026-01-20T23:22:29Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [January 20, 2026, 11:22pm UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/1 "2026-01-20T23:22:29Z")

</div>

Complaints about Prolog are nothing new, but this is a recent one (is anything in the gripes something we haven’t seen before?) by someone who’s writing a book _Logic for Programmers_ (which I haven’t yet read).

> **[My Gripes with Prolog](https://buttondown.com/hillelwayne/archive/my-gripes-with-prolog/)**
>
> It's not my favorite language

> **[Hillel Wayne](https://www.hillelwayne.com/)**

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [January 21, 2026, 8:27am UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/2 "2026-01-21T08:27:09Z")

</div>

I wonder if I should here in this thread reply in substance to the article you shared.

All gripes are valid, and each of them has been resolved in at least one way; the author does not yet know about it. But is it really worth it to go addressing each one individually?

Instead, I will use this forum to tell you my biggest gripe with SWI-Prolog: it does not have an authoritative exhaustive tutorial on its website. I am certain that the authoritative, exhaustive Python tutorial that lives at [python.org](http://python.org) was a major enabler for early adoption.

A good tutorial provides context, guidance, motivation of choices, best practices, in other words, does all the hand-holding that a novice requires. It is also, by definition, strongly opinionated. This is what makes it so difficult to write well.

---

<div class="post-metadata">

**Author:** ![dengqj](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/dengqj/32/6959_2.png) [@dengqj](https://swi-prolog.discourse.group/u/dengqj)\
**Post date:** [January 22, 2026, 11:45am UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/3 "2026-01-22T11:45:12Z")

</div>

Keep calm and treat each of Prolog’s ‘gripes’ as a quirky design choice that’s already been gently sidestepped in practice—then quietly keep loving (and occasionally grumbling about) the language anyway.

---

<div class="post-metadata">

**Author:** ![drspro](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drspro/32/3509_2.png) [@drspro](https://swi-prolog.discourse.group/u/drspro)\
**Post date:** [January 22, 2026, 11:46am UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/4 "2026-01-22T11:46:21Z")

</div>

> Now this is pretty cool in that it allows bidirectionality, or running predicates “in reverse”. To generate lists of length 3, you can write `length(L, 3)`. But it also means that if you want to get the length a list _plus one_, you can’t do that in one expression, you have to write `length(List, Out), X is Out+1`.

i quoted this text above from the Article. ( I am probably not aware of many possibilities of swi-prolog because I only work with it a few years )

but the answer to the above maybe only a question of _taste_.  
concerning this: length(List, Out), X is Out+1`.

in the Old V-prolog the length predicate syntax was like this : length( List , Out )  
in the new V-prolog syntax the predicate is like this: Out = length( List )  
( old syntax is not allowed anymore )  
because of this new syntax you can now write : X is length( List ) + 1.  
because of this possible nesting you get shorter code. but in my opinion if you continue deeper nesting in the same fashion the whole becomes unreadable  
( not easy to read ) because you mix procedural syntax to much inside logic syntax. In the new syntax you can ofcourse still write this:  
Out = length( List ) , X is Out + 1 .

for me as coming from V-prolog it was very new that in swi-prolog you can basically call any predicate inside the arguments of another predicate,  
( like in for example setup\_call\_cleanup( _,_,\_) ) .  
In the recent past i had to read swi-prolog code created by another programmer where everything was nested like this almost up to 5 ,6 , levels deep, and in my opinion this code was completely impossible to read, and to modify and to use and to change.

as last point i post here an image of a complete other (new) Language called metta ( which i think still dont understand because i cant understand certain constructs, let and let\_star ) but this language is actually Prolog in a LISP -(S-expression ) syntax, and they also want bidirectional variabel instantiation.  
Everything in this language is nested nested nested to unlimited levels, and I  
personally find that very hard to read. I prefer prolog predicates even if that takes (a lot) more code. Also the swi-prolog construct if then else ( with → and ; ) i find very odd , though i can get used to it .  
In this Image of this metta language They introduced the **let** and **let\_star** statement which makes the total of code impossible to read, because it is  
possibly a consequence of ( again ) inserting Procedural thinking Inside logical thinking which is just never desirable

 ![metta-01-22 11-47-17](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/b/b3dd8e25e748024afcfedb41cfd3b45c150b3821.png)

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [January 22, 2026, 12:41pm UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/5 "2026-01-22T12:41:51Z")

</div>

> [@drspro](#):
>
> for me as coming from V-prolog

What is V-Prolog? A search hints at a Python implementation called vprolog or Visual Prolog.

> [@drspro](#):
>
> you can basically call any predicate inside the arguments of another predicate

call/1 has been part of Prolog as long as I know it. apply/2 also, now mostly replaced by call/2..N. The _another predicate_ is limited to _meta predicates_, or better to the _meta argument(s)_ of such predicates. That allows for some abstraction, such as once/1, ignore/1, etc. as well as maplist/2..N, etc.

In general I’m not a big fan of too much nesting either. I do not use Lambda expressions as in `library(yall)` and I tend to make sure that the callable argument passed to meta predicates are just simple predicate calls, i.e., no general body terms. In my experience it makes the code more readable and easier to debug (the latter could of course be considered a shortcoming of the debugger).

Many of the gripes are well known in the Prolog community. Many have been addressed by several Prolog implementations, but unfortunately all in a different way. That is why we have the [PIP initiative](https://prolog-lang.org/ImplementersForum/), trying to get to more portable solutions for some of these. That is a tedious process due to the radically different viewpoints. We do make progress though 🙂

---

<div class="post-metadata">

**Author:** ![drspro](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drspro/32/3509_2.png) [@drspro](https://swi-prolog.discourse.group/u/drspro)\
**Post date:** [January 22, 2026, 12:57pm UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/6 "2026-01-22T12:57:54Z")

</div>

V-prolog is Visual-Prolog i was afraid to mention it in the orginal name 🙂

---

<div class="post-metadata">

**Author:** ![drspro](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drspro/32/3509_2.png) [@drspro](https://swi-prolog.discourse.group/u/drspro)\
**Post date:** [January 22, 2026, 2:15pm UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/7 "2026-01-22T14:15:42Z")

</div>

here is an example of this code:

lazy\_subtraction is called here with another predicate eval\_args inside one of its arguments, but with the ^ character here which is just a format separator, but its not a strange construction? normally you would create a prolog term for :

```prolog
RetVal1^eval_args( Eq, RetType , Depth , Self, Eval1, RetVal1 )  
 
like:

structu_pro( RetVal1 , eval_args( Eq, RetType , Depth , Self , Eval1 , RetVal1 ) )

```

?

```prolog
eval_args(Eq,RetType,Depth,Self,X,Y):-
    notrace(nonvar(Y)), var(RetType),
    super_safety_checks(copy_term(Y,YC)),
    get_type(Depth,Self,Y,WasType),
    super_safety_checks(must_det_ll(Y=@=YC)),
    can_assign(WasType,RetType),
    nonvar(RetType),!,
    eval_args(Eq,RetType,Depth,Self,X,Y).
eval_args(Eq,RetType,Depth,Self,X,Y):- notrace(nonvar(Y)),!,
   eval_args(Eq,RetType,Depth,Self,X,XX),evals_to(XX,Y).

eval_20(Eq,RetType,Depth,Self,['subtraction',Eval1,Eval2],RetVal):- !,
    lazy_subtraction(variant_by_type,RetVal1^eval_args(Eq,RetType,Depth,Self,Eval1,RetVal1),
                  RetVal2^eval_args(Eq,RetType,Depth,Self,Eval2,RetVal2),
                  RetVal).

eval_20(Eq,RetType,Depth,Self,['pred-subtraction',P2,Eval1,Eval2],RetVal):- !,
    lazy_subtraction(P2,RetVal1^eval_args(Eq,RetType,Depth,Self,Eval1,RetVal1),
                  RetVal2^eval_args(Eq,RetType,Depth,Self,Eval2,RetVal2),
                  RetVal).

lazy_subtraction(P2,E1^Call1, E2^Call2, E1) :-
    % Step 1: Evaluate Call1 to generate E1
    call(Call1),
    % Step 2: Use lazy_findall/3 to declare that all elements satisfying Call2 are supposedly in List2
    lazy_findall(E2, Call2, List2),
    % Step 3: Perform the subtraction logic
    % Only return E1 if it is not a member of List2
    \+ (member(E2, List2), call(P2, E1, E2)).

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [January 22, 2026, 3:04pm UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/8 "2026-01-22T15:04:58Z")

</div>

> [@drspro](#):
>
> `RetVal1^eval_args( Eq, RetType , Depth , Self, Eval1, RetVal1 )`

This **is** a Prolog term `(^(RetVal1, eval_args( Eq, RetType , Depth , Self, Eval1, RetVal1 ))`. I think it is a dubious choice as Var^Goal is used for existential qualification in bagof/setof as well as in `library(aggregate)`. There is nothing wrong using it for something else, but combined with a goal I’d consider it confusing.

> [@drspro](#):
>
> `notrace(nonvar(Y))`

Why notrace/1?? Pretty much the only reason for that is for toplevel predicates such as make/0. They use notrace(…), such that if you want to make while in trace mode you do not start tracing make/0.

> [@drspro](#):
>
> ```prolog
> lazy_subtraction(P2,E1^Call1, E2^Call2, E1) :-
> % Step 1: Evaluate Call1 to generate E1
> call(Call1),
> % Step 2: Use lazy_findall/3 to declare that all elements satisfying Call2 are supposedly in List2
> lazy_findall(E2, Call2, List2),
> % Step 3: Perform the subtraction logic
> % Only return E1 if it is not a member of List2
> \+ (member(E2, List2), call(P2, E1, E2)).
> 
> ```

This looks very fancy, but why create a lazy list and run member on it? I think this is the same as the code below, no? What am I missing?

```prolog
lazy_subtraction(P2,E1^Call1, E2^Call2, E1) :-
     call(Call1),
     call(Call2),
     \+ call(P2, E1, E2).

```

---

<div class="post-metadata">

**Author:** ![drspro](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drspro/32/3509_2.png) [@drspro](https://swi-prolog.discourse.group/u/drspro)\
**Post date:** [January 22, 2026, 5:17pm UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/9 "2026-01-22T17:17:57Z")

</div>

this is code i copied from a developers code, it is code which is used to implement a metta language interpreter. i find it a bit strange code and difficult to understand, therefore i posted it here to ask if this is ‘normal’ code, i didnt write this code myself. i can post the whole code-file but it is a bit large.

---

<div class="post-metadata">

**Author:** ![patham9](https://avatars.discourse-cdn.com/v4/letter/p/f08c70/32.png) [@patham9](https://swi-prolog.discourse.group/u/patham9)\
**Post date:** [January 31, 2026, 9:17pm UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/10 "2026-01-31T21:17:26Z")

</div>

Some of these design decisions may look odd at first, but that’s largely because many people don’t really grasp what Prolog is. They often assume it’s mainly a puzzle-solver, or they want “functions” simply because the FP language they know is built around that narrower construct too. As a result, they try to graft special-case syntactic sugar onto Prolog (as in Picat), which pollutes the language, undermines meta-programmability, and thereby defeats Prolog’s real strengths.

A common intuition is that “functions are more mathematical”, but in fact mathematics itself ultimately formalizes functions _within logic_. I’m only fine with function notation when the language remains relational and logical at the core.

In that context MeTTa is interesting: it keeps a Lisp-like functional and fully homoiconic surface while embracing the more powerful logic-based substrate for execution, and it shares the same dynamism and metaprogramming ambitions that make SWI-Prolog so amazing.

Best regards,

Patrick

---

<div class="post-metadata">

**Author:** ![drspro](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drspro/32/3509_2.png) [@drspro](https://swi-prolog.discourse.group/u/drspro)\
**Post date:** [February 2, 2026, 4:03pm UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/11 "2026-02-02T16:03:51Z")

</div>

so could it be said that Metta is actually Prolog but only in a different syntax,  
the Lisp -syntax?. because I thought i found that in metta they want  
also 2 way variabel instantiation .

Only I find the Let and Let star statements counter intuitive and very hard to read.  
At least there should be 1 of the 2 and not both because it is very confusing.  
In let they first extract a variabel which is actually Procedural thinking inside  
logical thinking. the let could be formed different and more logically ,  
for example with only 2 parenthesis which groups other atoms.  
also the match statement is very odd, it could be changed by a simpler atom  
with for example the ? character. this not to make metta more similar to prolog  
but to make metta have a simpler structure

I have an editor created with visual-prolog which understands and parses the metta -syntax ,  
and it could propose different structure and it can verify the whole metta program, for if the syntax is Ok, if all predicates have been declared, and if all the arities are correct.

this editor only runs in windows, or Linux Wine, so that is a small/big restriction.  
currently i want this editor to be able to read/parse metta as well as to read/parse prolog, then ultimately it could result in a sort a IDE for metta and prolog.

i have used other IDEs which lack many things

the editor is not ready yet, but you can download it here:

[download editor](http://www.healthsoftware.nl/content/metta_prolog_editor.zip)

if you want the VP source-code i should maybe make a github

---

<div class="post-metadata">

**Author:** ![drspro](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drspro/32/3509_2.png) [@drspro](https://swi-prolog.discourse.group/u/drspro)\
**Post date:** [February 3, 2026, 10:43am UTC](https://swi-prolog.discourse.group/t/hillel-wayne-my-gripes-with-prolog/9484/12 "2026-02-03T10:43:29Z")

</div>

I uploaded the whole Visual Prolog project with all the sources to a Github repository in the following link :

[Metta Prolog editor in Visual Prolog with source on Github](https://github.com/drspro/metta_prolog_editor_visual_prolog)

the current status is that it is far from complete as an editor because I wasted a lot of time trying to transpile metta code, a function which i abandoned at the moment that Petta was released. But here you have all the source , in the readme you can see how it should be run
