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).
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 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.
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.
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 writelength(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
What is V-Prolog? A search hints at a Python implementation called vprolog or Visual Prolog.
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, 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 ![]()
V-prolog is Visual-Prolog i was afraid to mention it in the orginal name ![]()
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 :
RetVal1^eval_args( Eq, RetType , Depth , Self, Eval1, RetVal1 )
like:
structu_pro( RetVal1 , eval_args( Eq, RetType , Depth , Self , Eval1 , RetVal1 ) )
?
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)).
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.
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.
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?
lazy_subtraction(P2,E1^Call1, E2^Call2, E1) :-
call(Call1),
call(Call2),
\+ call(P2, E1, E2).
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.
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
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:
if you want the VP source-code i should maybe make a github
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
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
