A general comment on Prolog programming

I’m taking a break from coding for a bit and I felt like sharing some thoughts about Prolog programming in general. None of this is to be taken too seriously. It’s just for some lively discourse.

Prolog is my favorite language. SWI-Prolog is my favorite (by far) implementation of it.

But I must confess I have to concentrate a lot harder when writing Prolog code than in a procedural language (my primary job). But everything has its trade-offs and what I find as a reward for that more intense level of concentration and exactness, is that debugging the code I’ve written is a lot, lot easier than in a procedural language.

It’s as if Prolog forces you to get your thinking correct. Than after a short burst of cleaning up a few (truly) minor syntax errors, and a slew of singleton variable errors, which are also very easy to correct, the code frequently runs fine the first time!

This is a true delight given the opposite experience I have when debugging a procedural program. That experience usually consists of wading through tons of nested function calls and trying to disentangle improperly coupled algorithms or data structures or flat out logic errors; each of which causes an unpleasant round of alterations in the code that frequently ripple upwards and downwards the code hierarchy, with the not so infrequent painful mass refactoring session.

What has the experience been for the rest of you, especially those whose primary coding job is in a procedural language? What is it about Prolog that you feel promotes this unique experience?

5 Likes

Thanks for sharing. The need to concentrate a lot harder should largely go away over time :slight_smile: Pieter Adriaans used to run a business called Sylogics which did most of their early work in SWI-Prolog. Sylogics was the first sponsor of the project which resulted in the first garbage collector :slight_smile: At some point the business got big and C++ got a hype and became the leading language. Pieter has stated several times that a big difference was that Prolog projects rarely exceeded the estimated time, while C++ programs often did.

That is the good news. Lack of typing and proper refactoring tools can make refactoring a hell and while it may be less often required it still cannot always be avoided.

3 Likes

Love that quote! :slight_smile:

I am curious, what would explain this … why where estimates better in line when coding was done in Prolog …

Dan

1 Like

We can probably only speculate on that. AFAIK there is not much research done on language comparison as to what it means for a normal development and maintenance phase. That is why it remains mostly belief or religion :frowning:

I’m an amateur, probably intermediate level Prolog programmer, so take it with a grain of salt. I find it easier to represent many problems in Prolog. There is a beautiful fluidity between representation of data and the computation. It took a long time to get here, but now that I have an adequate mental model of Prolog’s execution and I don’t get surprised too often, I find I can leverage it pretty easily. You get the benefits of homoiconicity for creating inner DSLs (DCGs, library(aggregate), etc.) without having to stab your eyes out (Lisp). Often it feels like just adequately describing the relationships between things in your problem is enough, the solution magically falls out.

I think this is what you mean by concentrating: in Java you start a project and you can write dozens of lines of code before you have even really started to think about your problem. In Prolog, you have a blank page, you must begin by thinking about how you’re going to represent things and their relationships. Often you find that your understanding of those relationships is incomplete. Prolog forces you to reckon with that early.

Sometimes you see a few lines of Prolog that make you aware that it is possible to be clever or funny or have a really deep insight and make Prolog do so much of the work that there’s almost nothing left for you to do. ...//0 is a good example in the evil pack, that weird 8 queens solution that was discussed on Stack Overflow last month is another. I am still frequently surprised by things you can do in a page or less of Prolog. Somehow it has continued to be magical to me and often brightens my day.

SWI in particular is wonderful because it “just works,” comes with a lot of cool toys (I haven’t learned how to use half the stuff in the standard library yet) and has excellent ergonomics (colorful TTY, output simplifications). We all owe Jan et. al. a huge debt for this amazing project, I can’t imagine what life would be like without it.

2 Likes

Nice …

Yes, i think, i experienced the relational thinking as well.

I am recently, also, curious about Mercury and what its approaches to (algebraic?) types and modes might do to thinking about problems.

Dan

Early on, there was some work on program comprehension (Soloway, comes to my mind),

(and a more recent paper doing fMRI studies to identify cognitive efforts during development: https://peitek.com/ICSE18_DS_Peitek.pdf)

Perhaps, it is indeed the gap between specification and implementation, that is much more narrow in Prolog – and hence the cognitive overhead in jumping between top-down and bottom-up interpretations is narrower.

In the end of the day, where is most programming time spent – in internal cognitive “comprehension loops” :slight_smile:

Dan

Agreed! And don’t forget the indispensable graphical debugger. I tried living with plain text “box debuggers” in the past and well, it was painful.

2 Likes

For debugging Prolog – when I find a defective predicate, it’s often easier to simply delete it and rewrite it from scratch.

But I might be abnormal … my favourite debugging tools are portray/1, print_term/3, and library(rdet). [And my editor is emacs.]

1 Like

All the time, or only for some complex term you want formatted in a particular way?

What does rdet do? I don’t see it in the reference manual listing:

https://www.swi-prolog.org/search?for=library

For complex and large terms (some of my terms have thousands of elements, but the default depth settings for terms don’t do what I want).

user:portray(Term) :-
    %% in the following, format/2 is used because
    %% print_message(warning, E) gives an infinite recursion.
    E = error(_, _),            % avoid trapping abort, timeout, etc.
    catch(my_portray(Term),
          E,
          format('EXCEPTION:portray(~q)', [Term])).

https://www.swi-prolog.org/pack/list?p=rdet

But what I really want (and have been too lazy to write) is something that catches both failure and non-determinicity.

1 Like