Features of good Prolog code? [closed]
Asked Answered
C

1

11

What are the design heuristics one has to master to write good Prolog? I've heard it takes an experienced programmer about two years to become proficient in Prolog. Using recursion effectively is part of it, but that seems to be a relatively minor hurdle. What exactly is it that gives programmers so much trouble? What should I be looking for in sample code to judge its quality?

Cameral answered 29/3, 2013 at 19:4 Comment(1)
For the 2 years see this recommendation - and it is not even about Prolog!Gummite
G
26

The major difficulty in writing good Prolog code lies in not only understanding but also adequately transmitting the intention or purpose of a program. In contrast to other programming languages there are several quite different kinds of Prolog code often within the same program. By confusing such levels bugs and problems ensue:

Pure, monotonic code. This code lies at the heart of Prolog. In such code a lot of algebraic properties hold, and the actual problems are described in the pure, ideal manner which Prolog is often advertised with. Yet, even in such parts certain procedural properties may surface, such as non-termination. Take as an example the commutativity of conjunction. In pure, monotonic code, ( A, B ) and ( B, A ) describe the same relation. The only differences may lie in different termination behavior and the sequence how answers appear. Ideally, the names of pure predicates communicate that the predicates are relations. Imperatives are definitely not a good choice here.

Side-effectful code. The other extreme is code that can only be understood by effectively executing it, either by machine or in the mind. There are no simple invariants in the program. But even in such parts, there might still be certain properties observed like steadfastness. Effectively such code is not much different to other programming languages.

Often, the side-effectful part "eats up" the pure side since programmers are used to an imperative, command-oriented do-this do-that thinking. To lean into the other direction, think of which properties you will lose or gain. Think how easy it will be to test your program: The purer a program the easier it is to test without any extra sandbox around. A simple toplevel query is good enough.

Some examples, how the pure side can be expanded at the expense of seemingly necessary side-effects:

Or simply these answers.

Edit: In your comment, you ask for "advice for learning". So here is some:

  1. Stick to writing pure, monotonic code only. You can only judge to choose one or the other side if you know both. I assume you have some previous experience producing side effects in some command-oriented language, but none with pure code. As a consequence this will mean that you will refrain from writing inherently non-monotonic code.

  2. Play with the toplevel. Imagine, the toplevel is the only way to access your programs. How would you formulate a problem such that it fits into this format? The SWI, Scryer and Trealla toplevel have been specifically designed to permit such light-weight interaction.

  3. Use for arithmetics. Don't use (is)/2, it makes your code much too moded.

  4. Enjoy the algebraic properties of pure, monotonic code. Think of it: You add a goal, no matter where, and still you can predict that this goal will specialize your program (and at best leaves it as is). You can - blindly - remove a goal, and still you know (part of) its effect.

  5. Study the notion of a to master non-termination.

  6. Do not use a step-by-step tracer/debugger, as it is offered in many Prologs. It only shows you the precise steps Prolog takes. It does not show you anything directly related to the meaning of the program. It reinforces a step-by-step thinking.

  7. Watch your language. The way how you talk about a program influences the way you think about it. So, if you use a lot of operationalizing language (like: This does this etc), chances are you reinforce the command-oriented view. There is a cleaner way of talking about things, but you need to find it. This is probably the hardest part.

Gummite answered 29/3, 2013 at 19:56 Comment(7)
Are you saying that the main difficulty is knowing when to use Prolog in a imperative or declarative manner for a particular sub-problem? I would expect that knowledge to come from a lot of experience with particular systems and particular problems. So I guess you couldn't give much general advice for learning.Cameral
@user287424: I suggested the question: How much properties will you lose or gain? How easy is the code to test? That is possible to answer for you too, although it will take some time to consider it in detail. Experience makes this certainly easier and faster, but you can start with this.Gummite
@j4nbur53 Monotonicity and steadfastness are not always related. Take as an example append/3's first argument: It is not steadfast, but still the definition is monotonic.Gummite
@j4nbur53: You are commenting an "advice for learning". There is no agenda.Gummite
If you need a big domain to prove your point, rather take: 7^7^7#>= abs(X)Gummite
@Gummite what definition of 'steadfast' are you using here? Did we ever come up with a definitive answer for what that term should mean? Cf https://mcmap.net/q/267625/-steadfastness-definition-and-its-relation-to-logical-purity-and-termination/4355474Doralynn
@JasonHemann: certainly not the latter but the former.Gummite

© 2022 - 2024 — McMap. All rights reserved.