Prolog - How do I get the tail to not be null - sorting

I have the following problem:
Define a predicate sorted(LL), that is satisfied when the list LL
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

#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 that sorted([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.

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]).

Related

Prolog - infinite loop

I want to check if element is in the middle of list.
I search middle element and next I check if is a member of list, but I get infinite loop.
My predicates:
remove_first([_,H1|T], [H1|T]).
remove_last([_],[]).
remove_last([H|T], [H|T2]) :- remove_last(T, T2).
remove_first_and_last([X],[X]).
remove_first_and_last(In, Out) :-
remove_first(In, Out1),
remove_last(Out1, Out).
middle([X], [X]).
middle(In, X) :-
remove_first_and_last(In, Out),
middle(Out, X).
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
is_middle(X, In) :-
middle(In, Out),
member(X, Out), !.
And when I call is_middle(1,[2,1,3]) then I get true.
But when I call is_middle(1,[2,2,3]) then I don't get a result. Interpreter don't interrupt the processing.
In a situation as yours, you have two options. Either wade through walls of text of traces as you can see in another answer, or try to reduce first what you have to understand. I prefer the latter for I don't like to read much.
But your major problem is this. You said:
And when I call is_middle(1,[2,1,3]) then I get true.
Yes, Prolog found a solution, but it did not find it once but infinitely many times. Just hit SPACE or ; to see this:
?- is_middle(1,[2,1,3]).
true
; true
; true
; true
; true
; ... .
So, already your first query was problematic. The best way to observe this, is to add false to this query:
?- is_middle(1,[2,1,3]), false.
loops.
Now, let's try to reduce the size of the query. We can narrow it down to:
?- is_middle(1,[1]), false.
loops.
With this we can now look at your program. Before anything else I'll remove the cut. It is misplaced anyway.
To understand what is actually happening, I will narrow down your program by inserting false into it. With these extra goals it is possible to eliminate a lot of unnecessary detail. And still, the remaining program called a failure-slice is of relevance to us, if it is still looping.
remove_first_and_last([X],[X]).
remove_first_and_last(In, Out) :- false,
remove_first(In, Out1),
remove_last(Out1, Out).
middle([X], [X]) :- false.
middle(In, X) :-
remove_first_and_last(In, Out),
middle(Out, X), false.
is_middle(X, In) :-
middle(In, Out), false,
member(X, Out).
Compare this to your original program! Much less reading. To fix the problem you have to fix something in the remaining fragment. I suggest to remove the fact remove_first_and_last([X],[X]). This fact suggests that something is removed, but for this very case, nothing is removed.
For a solution using a dcg directly:
is_middle(E, Es) :-
phrase(middle(E), Es).
middle(E) --> [E].
middle(E) --> [_], middle(E), [_].
That is as short as it can get, but it has a tiny problem: It does not compute the answer determinately. You can see this by looking at the answer:
?- is_middle(1, [2,1,3]).
true
; false.
This ; false is an indication that Prolog was not able to finish the computation determinately. In other words, some space is left. You might be tempted to use a cut. Resist!
If you are really into speed, take the fastest version:
is_middle(X, Xs) :-
Xs = [_|Cs],
middle_el(Cs, Xs, X).
middle_el([], [X|_], X).
middle_el([_,_|Cs], [_|Xs], X) :-
middle_el(Cs, Xs, X).
In case you want #DanielLyons' interpretation which admits even-length lists to have two middle elements, see how easy it is to adopt above grammar definition. Simply add the following two rules:
middle(E) --> [E,_].
middle(E) --> [_,E].
Alternatively, combine all four rules into one:
middle(E) --> [E] | [E,_] | [_,E] | [_], middle(E), [_].
For the fastest solution, things are a bit more complex ...
is_middle_dl(X, Xs) :-
Xs = [_|Cs],
middle_el_dl(Cs, Xs, X).
middle_el_dl([], [X|_], X).
middle_el_dl([_|Cs], Xs, X) :-
middle_el_dl2(Cs, Xs, X).
middle_el_dl2([], [A,B|_], X) :-
( X = A ; X = B ).
middle_el_dl2([_|Cs], [_|Xs], X) :-
middle_el_dl(Cs, Xs, X).
To check it, I use:
?- length(Xs, N), N mod 2 =:= 0, is_middle_dl(X, Xs).
Xs = [X,_A], N = 2
; Xs = [_A,X], N = 2
; Xs = [_A,X,_B,_C], N = 4
; Xs = [_A,_B,X,_C], N = 4
; Xs = [_A,_B,X,_C,_D,_E], N = 6
; Xs = [_A,_B,_C,X,_D,_E], N = 6
; Xs = [_A,_B,_C,X,_D,_E,_F,_G], N = 8
; Xs = [_A,_B,_C,_D,X,_E,_F,_G], N = 8
; Xs = [_A,_B,_C,_D,X,_E,_F,_G,_H,_I], N = 10
; Xs = [_A,_B,_C,_D,_E,X,_F,_G,_H,_I], N = 10
; ... .
Debugging Prolog takes some different skills, so let's take the long road there.
First, let's notice something interesting about your two sample queries. The first one succeeds, and it should; the second one should fail, but instead it loops. This tidbit is a clue: it suggests that we're trying to handle a false case. This is a common mistake among people using Prolog after other languages. In Prolog, it's often enough to be explicit about successful cases and just let failures happen through failed unifications.
The standard tool for debugging Prolog is trace/0. The idea is, you activate trace mode and then run your query, like this:
?- trace, is_middle(1,[2,2,3]).
The trouble with trace/0 is that it can take some effort to understand what's happening with it. Each line starts with one of these four verbs: call, exit, redo, or fail. Then there's a number which indicates the nesting level of the call. The call and redo verbs tell you that you're entering a computation; exit and fail tell you a computation is ceasing and the nesting level is about to decrease. Call/exit are the normal case, fail/redo are what makes Prolog special, the non-determinism. In general, an infinite loop will look like some prefix of meaningful work (or possibly not) followed by an endlessly repeating chunk of output from trace. And we see that here. Prefix:
Call: (8) is_middle(1, [2, 2, 3]) ? creep
Call: (9) middle([2, 2, 3], _G1194) ? creep
Call: (10) remove_first_and_last([2, 2, 3], _G1194) ? creep
Call: (11) remove_first([2, 2, 3], _G1194) ? creep
Exit: (11) remove_first([2, 2, 3], [2, 3]) ? creep
Call: (11) remove_last([2, 3], _G1197) ? creep
Call: (12) remove_last([3], _G1190) ? creep
Exit: (12) remove_last([3], []) ? creep
Exit: (11) remove_last([2, 3], [2]) ? creep
Exit: (10) remove_first_and_last([2, 2, 3], [2]) ? creep
Repeating chunk:
Call: (10) middle([2], _G1200) ? creep
Exit: (10) middle([2], [2]) ? creep
Exit: (9) middle([2, 2, 3], [2]) ? creep
Call: (9) member(1, [2]) ? creep
Call: (10) member(1, []) ? creep
Fail: (10) member(1, []) ? creep
Fail: (9) member(1, [2]) ? creep
Redo: (10) middle([2], _G1200) ? creep
Call: (11) remove_first_and_last([2], _G1200) ? creep
Exit: (11) remove_first_and_last([2], [2]) ? creep
Now you can see it would be much easier to trigger the bad behavior just with this query:
[trace] ?- is_middle(2,[3]).
Call: (7) is_middle(2, [3]) ? creep
Call: (8) middle([3], _G398) ? creep
Exit: (8) middle([3], [3]) ? creep
Call: (8) member(2, [3]) ? creep
Call: (9) member(2, []) ? creep
Fail: (9) member(2, []) ? creep
Fail: (8) member(2, [3]) ? creep
Redo: (8) middle([3], _G398) ? creep
Call: (9) remove_first_and_last([3], _G398) ? creep
Exit: (9) remove_first_and_last([3], [3]) ? creep
Call: (9) middle([3], _G401) ? creep
Exit: (9) middle([3], [3]) ? creep
Exit: (8) middle([3], [3]) ? creep
Call: (8) member(2, [3]) ? creep
Call: (9) member(2, []) ? creep
Fail: (9) member(2, []) ? creep
Fail: (8) member(2, [3]) ? creep
Redo: (9) middle([3], _G401) ? creep
Now it should be clear that the problem has to do with the interplay of middle/2, remove_first_and_last/2 and member/2. Your definition of member/2 is exactly the standard definition so it probably isn't to blame. Now, interestingly, you have middle/2 calling both itself and remove_first_and_last/2. And both middle/2 and remove_first_and_last/2 have an identical clause: m([X], [X]).
This kind of thing is a great generator of infinite recursion, because the first thing middle/2 does in its second clause is exactly what it just tried to do and failed with its own first clause. So it can find itself entering a recursive call in the second clause with exactly the same state it had in an earlier failed call to itself.
The solution is to look at remove_first_and_last/2 and realize that your first clause there does not actually remove the first and last element. Removing the remove_first_and_last([X], [X]) clause fixes the code:
[trace] ?- is_middle(2,[3]).
Call: (7) is_middle(2, [3]) ? creep
Call: (8) middle([3], _G398) ? creep
Exit: (8) middle([3], [3]) ? creep
Call: (8) member(2, [3]) ? creep
Call: (9) member(2, []) ? creep
Fail: (9) member(2, []) ? creep
Fail: (8) member(2, [3]) ? creep
Redo: (8) middle([3], _G398) ? creep
Call: (9) remove_first_and_last([3], _G398) ? creep
Call: (10) remove_first([3], _G398) ? creep
Fail: (10) remove_first([3], _G398) ? creep
Fail: (9) remove_first_and_last([3], _G398) ? creep
Fail: (8) middle([3], _G398) ? creep
Fail: (7) is_middle(2, [3]) ? creep
false.
Both your tests also now work:
?- is_middle(1,[2,1,3]).
true.
?- is_middle(1,[2,2,3]).
false.
I think you added the base case here out of a sense of duty to have one. But the reality is that if you have a list of one element, it should fail to unify with remove_first_and_last/2 under any circumstance. This is very similar to handling an error case explicitly with Prolog, which tends to interfere with the working of the machinery.
Now, one thing that's missing is, how do you want to handle even-length lists? What you have right now won't, with or without my change. Even-length lists don't have a middle element; is that what you intend? I suspect it isn't, because of the appearance of member/2 in is_middle/2.
Comments on is_middle/2
What you have here could be restructured like so:
is_middle(X, In) :- middle(In, [X]).
Usage of member/2 isn't buying you anything because middle/2 can't ever produce a non-singleton list in its second argument. But, if it did, because you had even-length lists, it would be profitable. You could even make this code work that way by adding a third clause to middle/2:
middle([X,Y], [X,Y]).
Now see middle/2 works on even-length lists like so:
?- middle([2,1,3,4], X).
X = [1, 3] ;
false.
Now the cut gets you into trouble though. For instance, 1 and 3 are both is_middle/2:
?- is_middle(1, [2,1,3,4]).
true.
?- is_middle(3, [2,1,3,4]).
true.
Unfortunately though, if you ask for middle elements, you just have 1:
?- is_middle(X, [2,1,3,4]).
X = 1.
What happened to 3? You prevented it from being generated with your cut. I am not sure why the cut is here. I think you must have put it in to try and control the infinite recursion, but it doesn't help you, so get rid of it.
Debugging by random addition of cuts is generally not a great idea. A much better approach is using Ulrich Neumerkel's failure slice approach (see this paper or search the tag for more information).
DCG bonus
You can rephrase remove_first_and_last/2 as a DCG rule:
remove_first_and_last --> remove_first, remove_last.
Pretty cool, huh? :) That's because the kind of input/output threading you're doing in that rule exactly what DCG rules get transformed into.
Summary of changes
remove_first_and_last(In, Out) :-
remove_first(In, Out1),
remove_last(Out1, Out).
middle([X], [X]).
middle([X,Y], [X,Y]).
middle(In, X) :-
remove_first_and_last(In, Out),
middle(Out, X).
is_middle(Item,List) :-
append(Left,[Item|Right],List),
length(Left,X),
length(Right,X).
Complex solutions are bad solutions, my friend.
?- is_middle(X,[1,2,3,4,5]).
X = 3 ;
false.
Fully reversible predicate:
?- is_middle(3,L).
L = [3] ;
L = [_G13, 3, _G19] ;
L = [_G13, _G19, 3, _G25, _G28] ;

Prolog unifying two lists

Alright, so I was trying to unify this two lists: [2] and [1,_,3] giving an answer of [1,2,3]. My code is below:
unify([],[],_).
unify(List1, [Head|Rest], List2) :- member(List1,Head),!,
unify([X|_], Rest, [X|List2]).
unify(List1, [Head|Rest], [Head|List2]) :- unify(List1, Rest, List2).
when i put ?-unify([2],[1,_,3],L) it gives me false, but I want it to give L=[1,2,3]. How can I improve the above code?
I tried a trace too but I couldn't figure out.
[debug] 5 ?- unify([2],[1,_,3],L).
T Call: (6) unify([2], [1, _G512, 3], _G520)
T Redo: (6) unify([2], [1, _G512, 3], _G520)
T Call: (7) unify([2], [_G512, 3], _G602)
T Call: (8) unify([_G607|_G608], [3], [_G607|_G602])
T Redo: (8) unify([_G607|_G608], [3], [_G607|_G602])
T Call: (9) unify([3|_G608], [], _G602)
T Fail: (9) unify([3|_G608], [], _G602)
T Fail: (8) unify([_G607|_G608], [3], [_G607|_G602])
T Fail: (7) unify([2], [_G512, 3], _G602)
T Fail: (6) unify([2], [1, _G512, 3], _G520)
false
First, you need to fix the base case: rather than using
unify([],[],_).
which says that an empty list on the left requires an empty list in the middle, and produces an undefined result, use these two:
unify(_,[],[]).
unify([],L,L).
The first base clause says that if the second list is empty, the output is empty as well, no matter what's in the first list.
The second base clause says that when the first list is empty, the output is the same as the second list.
Now we need to build two clauses that reduce the problem:
unify([H|T1], [H|T2], [H|R]) :- unify(T1, T2, R).
unify([H1|T1], [H2|T2], [H2|R]) :- H1 \= H2, unify([H1|T1], T2, R).
The first clause says that if the heads of the two lists unify, then attach the unified heads to the output of the reduced problem when both lists are reduced.
The second clause says that if the heads do not unify, then attach the head of the second list to the output of the reduced problem when only the second list is reduced.
Here is a demo on ideone.

Prolog: Compare 2 Lists and find out if at least one member of the first list exists in the other one

In the quest of learning more about prolog (and in the interest of solving my assignment), I have come across a situation where I need to compare 2 lists and find out if AT LEAST ONE element match ...
Here is an example what I want to do:
?-match([a,b,c],[x,y,z]).
no.
?-match([a,b,c],[x,y,b]).
yes.
My solution up to now:
compare_list([],[]).
compare_list([],_).
compare_list([L1Head|L1Tail],List2):-
member(L1Head,List2),
compare_list(L1Tail,List2).
but this solution gives a true when all the members of List1 are present in List2!
Please people, don't think that I am cheating on an assignment, the problem is much much more complex, I am just stuck at this point and need help to get out of this sticky corner... otherwise I have done the entire assignment myself!
your problem can be solved using the simpler builtins
match(L1,L2) :- member(E,L1),member(E,L2). % full join
add the nasty cut if you are really interested only in 'at least one' solution
match(L1,L2) :- member(E,L1),memberchk(E,L2),!. % really, just the first!
I'll comment on the attempt you've made, which is close, but not quite there:
compare_list([],[]).
compare_list([],_).
The first clause for compare_list/2 says that the empty list has at least one element in the empty list. The second says the empty list has at least one element in any other list. So the first clause is redundant (it's already covered by the second). Whether you want this to be true (that an empty list has an element in any other list) is up to you. Since an empty list has no members, one might consider this a failure case (and, thus, not be declared as true) but you can call it true by definition if you wish. However, it will cause some issues in the recursive case once you have your predicate correctly defined since reducing down to [] will become true and ultimately it might find any list has elements in any list (oops!). I'd leave these two clauses out and consider this case a fail.
compare_list([L1Head|L1Tail], List2):-
member(L1Head, List2),
compare_list(L1Tail, List2).
This says that the first list has an element in the second list if: (1) the head of the list is a member of the second list, AND (2) the tail of the first list has an element in the second list. Does this sound logically correct? If you think this through, given there are no additional compare_list/2 clauses, this is true only if EVERY element of the first list is a member of the second list, as you have observed.
Finally, you're missing the case where the first list has a head that is not a member of the second list. This shouldn't necessarily be a failure since the tail of the first list may have a member in the second list, even if the first element (head) is not a member.
Another way is to use nth0 predicate.
match(L1, L2) :-
nth0(_, L1, SharedItem),
nth0(_, L2, SharedItem).
The first nth0 says "is there a L1 list item with index '_' (ie don't care whether it is in first, second etc. position in the list), whose name is variable SharedItem.
The second nth0 does the same for L2.
But the nice trick is in the unification.. by using the same variable name SharedItem on both nth's, prolog will continue iterating through the lists until the same item is in both.
As always the 'trace.' predicate is your best friend.. run it before calling the above to see what prolog is doing in the background:
[trace] ?- match([a,b,c],[x,y,b]).
Call: (6) match([a, b, c], [x, y, b]) ? creep
Call: (7) lists:nth0(_G1965, [a, b, c], _G1967) ? creep
Exit: (7) lists:nth0(0, [a, b, c], a) ? creep
Call: (7) lists:nth0(_G1968, [x, y, b], a) ? creep
Fail: (7) lists:nth0(_G1968, [x, y, b], a) ? creep
Redo: (7) lists:nth0(_G1968, [a, b, c], _G1970) ? creep
Exit: (7) lists:nth0(1, [a, b, c], b) ? creep
Call: (7) lists:nth0(_G1968, [x, y, b], b) ? creep
Exit: (7) lists:nth0(2, [x, y, b], b) ? creep
Exit: (6) match([a, b, c], [x, y, b]) ? creep
true .
So the 'outer' loop is L1.. it first tries index 0 of L1(a), then when it fails to find it in L2, it does a Redo (of the first nth0), but this time with index 1(b), and finds it, then returns true.
Using your example predicate match/2. The solution is as simple as traverse recursively the List1 (on the left) and check if the Head belongs to the List2 via the memberchk/2 predicate. The reason to use memberchk/2 is that it succeeds only once (i.e., not re-executable on backtracking) and this is what your "AT LEAST ONE" condition states. If the List1 is empty, the predicate fails.
Code:
match([Head|Tail], List2):-
memberchk(Head,List2).
match([_|Tail],List2):-
match(Tail,List2).
Examples:
| ?- match([a,b,c],[x,y,z]).
no
| ?- match([a,b,c],[x,y,b]).
yes
| ?- match([a,b,c],[]).
no
| ?- match([],[x,y,b]).
no

Removing element from a list

I know this question has been asked already, but I just want to ask about my specific implementation. I'm writing this function just to practice Prolog and better understand Prolog. Here's what I have:
del(Ele, [H], [H]) :- Ele \= H.
del(Ele, [H|T], [H|New]) :-
Ele \= H,
del(Ele, T, [New]).
The idea is that I will add an element to a new list called New if the element I want to delete is not equal to H. From what I understand, my code isn't working because my code stops when I reach an element where Ele \= H. Any ideas how to fix this?
For example, del(5, [3,4,5,6,7], X) will return false.
Also, are there any better solutions? It seems like a bad solution to keep adding every element in a list to a new list, since this would be slow for a large list. I'd rather just keep the elements currently in the list, find element(s) that match Ele, remove that element, and then return the list.
You have described some cases where del/3 should hold. But these are only cases where Ele is not equal/unifiable to the elements in the list. There are several things missing:
What about the empty list?
What, if Ele is equal to the element?
So you need to add further clauses. (Later you might also remove some, for reasons of redundancy).
If you are using SWI, B, SICStus, or YAP, consider to use dif/2 in place of (\=)/2. prolog-dif
Here is the reason why dif/2 is so helpful in this case. With dif/2 you would have a pure monotonic program. And you could try it out directly:
?- del(5, [3,4,5,6,7], X).
false.
The same problem you had. Let me just restate what the problem is: You expect that something should hold, but it does not. So the relation is too narrowly defined. If I generalize the query, I might get a better answer. Try del(E, [3,4,5,6,7], X). but again the same false. So I'll try an even more general query:
?- del(E, Xs, Ys).
Xs = Ys, Ys = [_A], dif(E,_A)
; ... .
Looks perfect to me! Maybe another answer:
?- del(E, Xs, Ys).
Xs = Ys, Ys = [_A], dif(E,_A)
; Xs = [_A,_B], Ys = [_A|_B], dif(E,_B), dif(E,_A)
; ... .
Now we got an incorrect answer. I will instantiate it a bit to make it better readable:
?- del(e, [a,b], Ys).
Ys = [a|b]
; false.
This answer is clearly incorrect because [a|b] is not a list. And, it's probably the smallest incorrect answer...
What I want to show you by this is that you can most often locate problems without going through it step-by-step. Step-by-step debugging does not even work in imperative languages once you get a more complex control flow (like concurrency) ; and it does not scale at all in Prolog.
Let's trace:
?- trace, del(5, [3,4,5,6,7], X).
Call: (7) del(5, [3, 4, 5, 6, 7], _G218) ? creep
Call: (8) 5\=3 ? creep
Exit: (8) 5\=3 ? creep
Call: (8) del(5, [4, 5, 6, 7], [_G344]) ? creep
Call: (9) 5\=4 ? creep
Exit: (9) 5\=4 ? creep
Call: (9) del(5, [5, 6, 7], [[]]) ? creep
Fail: (9) del(5, [5, 6, 7], [[]]) ? creep
Fail: (8) del(5, [4, 5, 6, 7], [_G344]) ? creep
Fail: (7) del(5, [3, 4, 5, 6, 7], _G218) ? creep
false.
So you can see your code is actually failing when it gets to the 5 because 5 \= 5 is false. Your first rule is never matched because the list has more than one item in it. The second rule recurs "correctly" after finding 5 \= 3 and 5 \= 4 but since you have no 5 = 5 case in any of your rules, the failure happens there.
Incidentally, let's see what happens when 5 does not occur in the list:
?- trace, del(5, [3,4,6,7], X).
Call: (7) del(5, [3, 4, 6, 7], _G350) ? creep
Call: (8) 5\=3 ? creep
Exit: (8) 5\=3 ? creep
Call: (8) del(5, [4, 6, 7], [_G473]) ? creep
Call: (9) 5\=4 ? creep
Exit: (9) 5\=4 ? creep
Call: (9) del(5, [6, 7], [[]]) ? creep
Fail: (9) del(5, [6, 7], [[]]) ? creep
Fail: (8) del(5, [4, 6, 7], [_G473]) ? creep
Fail: (7) del(5, [3, 4, 6, 7], _G350) ? creep
false.
This is why I said "correctly" before: your inductive case isn't right either. For one thing, you have del(Ele, T, [New]) but up above you have del(Ele, [H|T], [H|New]) so you're unwrapping the list an extra time on the right (this is why our trace has [[]] in it). But #false hit the larger issue which is that you simply never account for the case where you actually find what you are looking to delete. :) You also don't handle the case where the list is empty.
It is an unfortunate fact of life that traversing data structures and looking at each item is going to be O(N). Another unfortunate fact is that in functional and declarative languages (languages that lack "assignables") modifying a list means copying at least part of the list. There are more efficient ways to go about this in Prolog (you could use difference lists, for instance) but they will share the same basic problem. Prolog efficiency is a rather large topic. I'd tell you to not worry about it too much up front, but it has a way of becoming your concern pretty quickly. But in this case, no, there isn't really a substantially more efficient approach using destructive updates.

what does the follow prolog codes do?

I am having trouble understanding the codes below.
Can someone explain step by step what is happening if I have the follow input:
append([1,2,3], Lst).
Actually, I don;t get how 1 and 2 is appended the list Lst as a result.
append([_], []).
append([H|T], [H|N]) :- append(T,N).
It sounds like you're new to Prolog. If so, welcome! Let's analyze this.
This unfortunately-named function has two clauses. Prolog looks at the clauses in order to see which one applies. When it finds one that matches, it tries to perform it. If there's a failure somewhere in performing it, it will back up and try the next option. Where precisely these choice points are varies depending on the program; in this program, the only one will be at the clause level, deciding which rule to use.
One way of looking at the first rule is that it is saying "A list with one element, regardless of what that element is, is related to the empty list." Looking at append([_], []), if we had X = [foo] and Y = [], it would hold, because [foo] is a one-item list and [] is the empty list. This rule is good Prolog style, because it will work regardless of instantiation: we could supply the left or the right or neither, it doesn't matter.
The second clause is also quite simple. It says that the left argument and the right argument are related if they both start with the same item, and if the rest of the lists are also related by this same predicate. In other words, if I have two lists X and Y such that append(X, Y) is true, then append([H|X], [H|Y]) is also true. It doesn't matter what H is and it doesn't matter what X and Y are, except insofar as would be implied by append/2.
Thinking logically, if I know that any one-item list is related to the empty list, and any list is related to a list that starts with the same item and otherwise is the same, the only kinds of lists that can be so related are lists where every item is the same, except the left list has one more item in it at the end which is not present on the right. So [1,2,3,4] is related to [1,2,3], but so is [1,2,3,foo] and [1,2,3].
Procedurally, let's look at what happens as this predicate is processed with this set of arguments:
append([1,2,3], X).
The first rule won't match on [1,2,3]. So we must look at the second rule:
append([1|[2,3]], [1|X]) :- append([2,3], X).
We can repeat:
append([2|[3]], [2|Y]) :- append([3], Y).
Now the first rule does match:
append([3], []).
So putting it all together:
append([1,2,3], [1|X]) implies
append([2,3], X=[2|Y]) implies
append([3], Y=[])
so Y = []
so X = [2]
so the right side is [1,2].
A Prolog trace will show you basically the same information:
?- trace, append([1,2,3], X).
Call: (7) append([1, 2, 3], _G1633) ? creep
Call: (8) append([2, 3], _G1752) ? creep
Call: (9) append([3], _G1755) ? creep
Exit: (9) append([3], []) ? creep
Exit: (8) append([2, 3], [2]) ? creep
Exit: (7) append([1, 2, 3], [1, 2]) ? creep
What makes this Prolog code confusing is that it doesn't look like you've told Prolog how to do anything. And it's true, you haven't, but by specifying what is true logically, Prolog is able to figure it out by itself. This is pretty clever code. If this were Haskell, we'd be talking about the built-in function init, which returns all of the list but the last item.
Hope this helps!

Resources