问题
I have the following problem:
Define a predicate
sorted(LL)
, that is satisfied when the listLL
contains other lists that are sorted in order of increasing length. For example:?- sorted([[],[1],[1,1],[1,1,1]]) -> yes. ?- sorted([[],[1],[1,1]]) -> yes. ?- sorted([[1],[],[1,1],[1,1,1]]) -> no.
And I have this code so far:
% shorter/2
shorter([],_).
shorter([_|T1], [_|T2]) :- shorter(T1,T2).
% sorted/1
sorted([]).
sorted([_]).
sorted([L1,L2 | T]) :- shorter2(L1, L2), sorted([L2,T]).
The problem is contained in the above line: sorted([L2,T])
. When only one element is left in the list of lists, that call will append an empty list []
because of which shorter/2 will fail. It is depicted in the following SWIPL trace.
[trace] ?- sorted([[1],[2,3]]).
Call: (6) sorted([[1], [2, 3]]) ? creep
Call: (7) shorter2([1], [2, 3]) ? creep
Call: (8) shorter2([], [3]) ? creep
Exit: (8) shorter2([], [3]) ? creep
Exit: (7) shorter2([1], [2, 3]) ? creep
Call: (7) sorted([[2, 3], []]) ? creep <-- empty list appended
Call: (8) shorter2([2, 3], []) ? creep
Fail: (8) shorter2([2, 3], []) ? creep
Fail: (7) sorted([[2, 3], []]) ? creep
Fail: (6) sorted([[1], [2, 3]]) ? creep
回答1:
You have two typos in the last clause of the sorted/1
predicate, which should be:
sorted([L1,L2| T]) :- shorter(L1, L2), sorted([L2| T]).
回答2:
@PauloMoura already gave you the right answer. Is there anything to learn about this? How did you encounter that problem? And how can you locate such problems systematically? I assume that you did not jump into the debugger to look at all those traces for sheer curiosity and a low on supply of animated gifs.
You rather encountered a problem. That is, you had the goal sorted([[1],[2,3]]).
which you expected to succeed, but it did not. So you had here some unexpected failure. Sometimes also called insufficiency or incompleteness. This means that the definition for sorted/1
is too specialized, it describes a set of solutions that is too small — at least it misses sorted([[1],[2,3]])
.
It often helps to minimize the problem, first. Also sorted([[],[3]])
fails, although we expect it to succeed. And sorted([[],[]])
even loops.
Understanding non-termination
Loops? That's often even easier to localize in a pure Prolog program. I will add goals false
and goals like T = []
into the program. The resulting program fragment (called a failure slice) certainly will become completely dysfunctional. But it will retain a very nice property. For: if this new fragment loops, then also the original program will loop. Here is that program that still loops:
?- sorted([[],[]]), false.sorted([]) :- false.sorted([_]) :- false. sorted([L1,L2 | T]) :- T = [], L1 = [], L2 = [], shorter(L1, L2), sorted([L2,T]). shorter([],_).shorter([_|T1], [_|T2]) :- false,shorter(T1,T2).
in other words:
sorted([[],[]]) :-
shorter([],[]),
sorted([[],[]]).
So, procedurally speaking, that rule does not (always) reduce the length of the list.
Concluding reading
Another way to understand the problem is to read the recursive rule right-to-left in the direction the arrow is pointing. Actually, :-
is meant to symbolize ←, well, 1970s style (listen to this French 1972 summerhit to until you understand). So let's try this. I will read:
sorted([L1,L2 | T]) :- shorter2(L1, L2), sorted([L2,T]).
^^^^^^^^^^^^^^ starting here
I start on the right side and interpret this as:
Provided,
sorted([L2,T])
is true.
Maybe some extra remark: Now, you might get pretty uneasy. You might say: Who knows this? Maybe that is not true at all! But the point is, it's just conditional. OK?
and provided
shorter(L1, L2)
is true
then, we can conclude thatsorted([L1, L2|T])
is true.
So we take a list of length 2 as granted and conclude that a list of length 2 or more holds as well.
But where do we actually state that a list of length 2 holds? There is no other place than this rule. Thus: Nowhere is this stated. And thus lists of length 2 or longer will never be sorted.
来源:https://stackoverflow.com/questions/26726484/prolog-how-do-i-get-the-tail-to-not-be-null