4 ms·
In my experience, the trick is to let go of the imperative reading since it becomes too complex in the situations you mention. Instead, focus on declarative pr
by triska 8y ago
In my experience, the trick is to let go of the imperative reading since it becomes too complex in the situations you mention.
Instead, focus on declarative properties: Does your predicate (or DCG) succeed in cases it shouldn't? Then your program is too general, and you need to add constraints. Or does your predicate fail in cases it should succeed? In that case, at least one of the goals is too specific. You can use declarative debugging to find out which goals are responsible for the failure.
You can add the following definition to your program to "generalize away" a goal by simply putting a * in front:
:- op(920,fy, *).
*_.
For example:
pred :-
true,
false.
?- pred. now fails. Why? To find out, try to locate the reason for the failure by generalizing away goals. For example:
pred :-
true,
* false.
This succeeds. So the last goal was responsible for the failure.
GUPU finds such fragments automatically for you! In a very precise sense, they are explanations for the problem. I know of no other programming language that admits this approach.
- YeGoblynQueenne 8y ago>> Instead, focus on declarative properties: Does your predicate (or DCG) succeed in cases it shouldn't? Then your program is too general, and you need to add constraints. Or does your predicate fail in cases it should succeed? In that case, at least one of the goals is too specific. You can use declarative debugging to find out which goals are responsible for the failure. That's good advice and I realise it articulates the way I reason about why my programs fail when they do (which is all the time). The problem is when reasoning doesn't shed any light on what's wrong. There are many such situations for me, often caused by the fact that Prolog still manages to surprise me even after many years of programming in it. For example I recently found out that findall/3 (which I use liberally) actually copies terms with fresh variables causing subtle changes to the structure of a term that are hard to detect with the naked eye. It took me I think an hour or so of debugging my code until I realised (and accepted) what was going on and I still had to go on to the Swi mailing list and ask, just to be sure. This is not something you can reason about, unless you know the semantics of a specific predicate (in this case, findall/3) in detail. In another recent example I was debugging code that backtracked over the combinations of a set, waiting for that one combination that caused the problem to reveal itself. It's very difficult to just reason about situations like this, when almost everything works but there is a subtle bug hiding in the wings.
- nickpsecurity 8y agoThat sounds like it could benefit from Design by Contract since it tells you in a lightweight way what a function will do. I actually submitted something like that to Lobste.rs recently when collecting all the implementations of contracts I could in various languages. Here's that one: https://www.krin.gs/files/papers/krings_plspec_declare17.pdf https://www.krin.gs/files/papers/krings_plspec_declare17.pdf
- samwalrus 8y agoThe thing is findall/3 is not really in the standard pure part of Prolog. It has the form: findall(Template,Enumerator,Instances), and can be read as: `Instances is the sequence of instances of Template which correspond to proofs of Enumerator in the order which they are found by the Prolog system" (Craft of prolog) This reading is meta logical because it depends on the instantiation of variables in Template and Enumerator and on the proof strategy of the Prolog system. So for example if you used a meta interpreter to change the search strategy of Prolog from topdown to bottom up, then the result of a call to findall would change. setof/3 does not have this problem because it finds the ordered set and can fail (in contrast to findall which will return an empty list) You need to bear in mind we as programmers are concerned with answers to a query but Prolog returns proofs... I now try and avoid findall/3 in my programs and only use it when I am doing input and output from my core program.