In the code given below, there is the !
(cut) that prunes the choice point for efficiency. I am pretty certain that the reverse
predicate and the agent_do_moves
predicate are essential.
solve_task(Task,Cost):-
agent_current_position(oscar,P),
solve_task_a(Task,[b(0,0,P)],[],R,Cost,_NewPos),!, % prune choice point for efficiency
reverse(R,[_Init|Path]),
agent_do_moves(oscar,Path).
The cut in above examples has the following effect:
Ideally, it commits the search which might happen within
solve_task_a/6
to the first answer found. This frees resources for finding further answers which improves space consumption.Scope problems
However, at the same time, it might also hide further answers to
agent_current_position/2
. Of course, it does not make much sense to have further answers for this goal, but it might be an error that happens to sleep for a while, only to become active but still undiscovered in the worst possible situation.For this reason, it would be preferable to write instead of the cut
This limits the scope precisely to what you want to express.
Steadfastness problem
But this is not the only possible source of problems. I see this variable
Cost
. Will it be instantiated when you callsolve_task(Task, Cost)
or not? I could do a lot of guessing here. But at least this variable might influence the answer Prolog will commit to. Sosolve_task(Task, 99)
andsolve_task(Task, Cost), Cost = 99
might produce different answers. In fact, the latter might even fail. Predicates that have such problems are said to lack steadfastness.To illustrate how steadfastness is easily lost in such a situation consider this (runnable) sketch of your (already improved) program:
Now
There would be an easy way out of this problem by cleanly testing variable
Cost
, e.g.Cost >= 0
which produces an instantiation error shouldCost
be an uninstantiated variable. But if you want (as you indicate in your comment) to determine the cost, you need to put it like so:In this manner we can be sure that
Cost
cannot influence the outcome ofsolve_task_a/6
(euh - provided there is no aliasing betweenCost
andTask
- but let's assume that for the moment). One says also that output unifications are put behind the commit.Many people will tell you that such extra care is not needed, as you will never use
solve_task(Task, Cost)
with a given cost. That might be the case, but are you sure you will remember it? And are you sure the source code will remember it (without any dynamic check)? Such implicit assumptions easily accumulate to a degree were your mental capacities are overburdened.There is not always an easy way out. But quite often it is possible to stick to logical purity logical-purity. In that case, you do not have to remember any such assumptions.
In any case, I would recommend that you do not go into these parts of Prolog for the moment. Rather stick to successor-arithmetics, clpfd, and other clean, monotonic programs preserving logical-purity. There is a lot to learn!