Prolog - understandig the use of cut - prolog

I can't understand clearly the use of cut. For example in this case: flatten, is it really needed? It works for me even without both cut predicates (I tried removing). What are the cases that can cause the backtracking going to the cut?
Removing the cuts you have the same implementation of the book "The art of prolog" (Shapiro E.,Sterling L.) that is:
flatten([X|Xs],Ys) :-
flatten(X,Ysl),
flatten(Xs,Ys2),
append(Ys1,Ys2,Ys).
flatten(X,[X]) :-
constant(X),
X\=[].
flatten([],[]).
which leads me to another question: is it necessary in the second clause to check if it's not a list? If it's a single term won't unify with the first clause...isn't it?

The program linked in your question uses cut ! operator to prevent the code in the answer from unifying with other clauses. Without these cuts flatten2/2 from the answer would unify an empty list in the first argument with clauses one and three, i.e.
flatten2([], []) :- !.
flatten2(L, [L]).
Similarly, without a cut in the second clause flatten2/2 would unify a non-empty list in clauses two and three, leading to incorrect behavior.
Your code, on the other hand, has explicit checks to ensure that each clause of flatten/2 deals with one specific situation:
First clause recursively flattens non-empty lists
Second clause makes a single-item list from constants other than empty lists
Third clause "flattens" empty lists.
Since each clause applies exclusively to a single type of item on the left, the cut is not necessary. You could have rewritten your code with a cut by switching the second and the third clause, and adding a cut after matching an empty list, but I would strongly recommend against doing this (demo).
is it necessary in the second clause to check if it's not a list?
This check is necessary because an empty list [] is considered a constant, so your program would have incorrect behavior when empty lists are present in the list being flattened (demo).

Related

Prolog checking if 2 lists have same number of elements

I am trying to figure out how to do this little thing. I have 2 lists for example [1,1,2,3,4] and [2,1,4,3,1], I need to confirm if all elements from list 1 are included in list 2, soo if i give the above lists as input this should be true, but if its like this [1,1,2,3,4] and [2,1,4,3,1,1] (three 1's) it should give false, this has to be done without using sort function.
I assume you know how to write a list as head and tail ([H|L]).
So you could use the predicate member/2 to ask for every element from the first list to be in the second list as well, but this would not solve the issue of duplicates. Using the predicate length/2 will not help in this case. So you need something that retracts one matching element from a list. You can either write your own find-and-remove-predicate or use the predicate append/3 to do so. append/3 is thought to append 2 lists to form a third one, but it can also be used to divide one list into two. If you state that your element as the head element of the second divided list you basically get a 'remove element' functionality. Once you've got the 2 divided lists, combine them into a new list and call the predicate again, but this time without the head element from list one and with the reappended-list. So in each step you remove one element from each list until you finally hit two empty lists (permut([],[]).). If something other than this two cases should appear, then the two lists are not permuations of each other and the predicate fails.
Since there is no use in backtracking other positions I inserted a cut (!) after successfully finding an element in the second list. The predicate works without the cut as well.
permut([],[]).
permut([H|T], Compare):-
append(C1, [H|C2], Compare),
!,
append(C1, C2, Cnext),
permut(T, Cnext).
gives the output
?- permut([1,2,3,4,5],[5,4,3,2,1]).
true.
?- permut([1,2,3,4,5],[5,4,3,2,1,1]).
false.
?- permut([1,2,3,4,5,6],[5,4,3,2,1]).
false.

Delete from list in SWI-Prolog

I'm beginner in SWI-Prolog and I have a problem. Please help me.
How can I delete the last occurence of 9 from a list?
Examples:
?- delete([9,9,9])
[9,9]
?- delete([9,4,1,2,3,9,53,2,9,2])
[9,4,1,2,3,9,53,2,2]
You have to 1) decompose the list into a Prefix list (which may contains 9s), a [9] one-element list and a Suffix list (which contains no 9s), then concatenate the Prefix and Suffix lists. Write a predicate which discovers the Prefix and the Suffix given a list L.
If we don't think procedurally or along the line of "how much is that gonna cost in CPU", the predicate decompose(List,Prefix,Suffix) which discovers Prefix and Suffix can be written in one single clause, a pure logical statement, using append/2 and member/2 and negation as failure.
One just needs a second line to cover the case where there are no 9s in the List to start with.

Get all Prefixes of a List, including [] in Prolog

I am new to Prolog and wanted to start learning the functionality of [H|T] by trying to write the prefix function on my own. The prefix function returns all possible prefixes to a list, such as for L = [a,b,c] would be [], [a], [a,b] and [a,b,c]. I am confused about how my own Prolog function would be able to return so many different solutions. I have it splitting the head and tail of the list, and appending the head to my new list that is going to be the different prefixes returned. This is what I have so far, but I think I am oversimplifying, and don't know how else to recursively call it to get all the different possibilities.
myPrefix([],[]).
myPrefix([H|T],List) :- myPrefix(T, [H|List]).
I looked at a lot of the other answers, but those just deal with getting the first element off of a list, not listing all possible prefixes. Any advice of how to go from here or more explanation as to how this head and tail of list manipulation functionality works is appreciated.
Assuming the first argument if instantiated is indeed is a proper list, then this should do it:
myPrefix(_, []).
myPrefix([H|T], [H|NT]):-
myPrefix(T, NT).
First clause ignores the first argument and unifies the second with the empty list.
Second clause takes the head of first argument list and puts it as the head of the second argument, and calls itself recursively.
So in effect, the second clause takes one by one as many items as desired and the first clause drops the tail.

What does '!' do in Prolog?

I keep running across this operator. Here is an example, a predicate that uses insertion sort to sort a list of integers.
inser(A,[],[A],P).
inser(A,[H|L],R,P):- P(A,H),append([A,H],L,R),!.
inser(A,[H|L],[H|R],P):- inser(A,L,R,P).
sortin([],[],P).
sortin([H|L],Re,P):- sortin(L,R,P),inser(H,R,Re,P).
I am new to Prolog.
That's called cut. Citing from SWI-Prolog documentation page:
Cut. Discard all choice points created since entering the predicate in which the cut appears. In other words, commit to the clause in which the cut appears and discard choice points that have been created by goals to the left of the cut in the current clause
The name is descriptive WRT the abstract computation model of Prolog, that builds a proof tree attempting to satisfy all conditions in a well defined order. The cut prunes potential branchs that application of alternative rules could require.
In your inser/3 predicate, it means that the third clause will not be tried if P(A,H) succeeds and append([A,H],L,R) succeeds as well.
Note that P(A,H) is not valid Prolog syntax. You should use call(P,A,H) to invoke P comparison predicate.

Manipulation with list

I am trying to understand prolog through examples. I wrote a piece of code but it is not working in desired manner and I am unable to find the fault.
list([]).
test([],_,_).
test([Child|List],B,C) :-
append([Child],B,C),
test(List,B,C).
testme :-
list(Final),
test([1,2,3],Final,Result),
write(Result).
The functionality which I require from this code that the Result should be the reverse of input list. When I trace this code I found the reverse of input list in C but it is not returned.
I knows using reverse function I can easily find reverse of list but my interest is not in finding the reverse but to understand this code and working of prolog. So please can someone tell me where I am wrong and what modification is required in this code to work properly.
First let's see why your code does not work.
test([],_,_).
test([Child|List],B,C) :-
append([Child],B,C),
test(List,B,C).
You tried to define a recursive predicate with two clauses.
The arguments to this predicate are: the input list (1), an intermediate list (2) and the final result(3).
Your first clause is thus, wrong.
Suppose your input list is just an empty list. The result should be an empty list. But in your first clause you are leaving the third argument as-is. Either it was already bound to somenthing (not useful in this case) or it was unbounded and therefore it will keep that way.
The second clause deals with recursion. It takes the first element of your input list, append it in the front of the intermediate list yielding another intermediate list.
Now you do the recursion step calling test again. But note that now the three arguments are instantiated! so you won't be able to append another item to the final list.
Here goes your test/3 predicate modified to work as you expect:
test([],List,List).
test([Child|List],B,D) :-
append([Child],B,C),
test(List,C,D).
Now the first clause just unifies the second and third argument.
So in our first test case (empty input list), recall that the second argument was also an empty list, so the third argument will also be an empty list => correct.
Now for the recursive clause.
It will take the first element of the input list and append it to the intermediate list, and unify it on a fresh variable.
Now we go into the recursion step, but now we use that list (C) as the intermediate list.
This, on recursion, will build the output list, now bound to D which is what we use as output.
As you are just appending one element to the intermediate list each time, you could have got rid of the append with something like:
test([],List,List).
test([Child|List],B,C) :-
test(List,[Child|B],C).
Prolog rules can only "return" values (since there is really no distinction between parameters and return values) by unifying them with their arguments. Assuming you want an accumulator-based reverse operation, you will need three parameters to test, and it should act as if it was written as:
test(A, B, C) :- reverse(A, A2), append(A2, B, C).
Having an implicit append operation in test will make the recursion easier to write. Also, note that you can write append([A], B, C) as C = [A | B] (or replace C by [A | B]).

Resources