I'm attempting to write a predicate to remove elements from an ordered list in Prolog. This is part of a homework assignment and I'm very confused about how Prolog's semantics work in general.
When I try the following function with the goal rdup([1,2], L). I get false. I've traced the goal and it looks like I'm not supposed to be building up the result list the way I am building it up with recursive calls to rdup. I'm not certain how I should be building up the result list. Here's the function:
rdup([],M).
rdup([X],[X]).
rdup([H1,H2|T], M) :- H1 \= H2, rdup(T, [M,H1,H2]).
rdup([H1,_|T], M) :- rdup(T, [M,H1]).
Can anyone tell me where my reasoning is wrong or how one is supposed to build up a list recursively in Prolog?
Firstly, it's not functions.
It's predicates, they only say, what's true, what's not, and under what conditions.
Here are your program:
rdup([],[]).
rdup([X],[X]).
rdup([H,H|T], M) :- rdup([H|T], M).
rdup([H1,H2|T], [H1|M]) :- H1 \= H2, rdup([H2|T], M).
Now a little bit of explanation.
Firstly, what says "rdup(X,Y)"? It's not saying "Take ordered list in X, and put list X without duplicates in Y", but it says "This fact will be true, if Y is an list X without duplicates, in assumption that X is an ordered list". Notice, that we don't talk about "returning values" or sth like that.
First line says, that the empty list is a list without duplicates of empty list. Quite obvious, right?
Next line is basically the same, but with one element.
Third line says, that if we have list, which consists from two same elements H and tail T, then the ordered list of this list ([H,H|T]) is the same, as it would be with only one element H. That's why we have "M" in both predicates unmodified.
I hope you will analyse the last predicate on your own, Prolog is not as hard as it looks to be. Good luck!
Related
I have a number of lists containing letters and I have written a predicate that checks whether or not there are duplicates present in one of these given lists:
noDuplicates([]).
noDuplicates([H|T]):-
not(member(H, T)),
noDuplicates(T).
I have 10 lists and I want to know if there are no duplicates in any of them, so I made them into sublists of one big list, something like:
[[A,B,C], [C,A,D], [E,F,G]...]]
(So there can be duplicates in the big list, but not the individual sublists).
I get that I have to do the duplicates test 10 times; once for every sublist, but how do I write this in Prolog? I could probably write it down 10 times, but my guess is I can use recursion to make prolog repeat itself until all sublists have been checked.
So basically: I want this predicate to repeat itself N times, until N is 10. I'm really struggling with it though. Does anyone have any idea on what to do?
Let us generalize the question as follows:
You have a predicate p/1 that expresses what you want for a single list.
Thus, to lift this definition to a list of such lists, you can define a predicates ps/1 as follows:
ps([]).
ps([L|Ls]) :-
p(L),
ps(Ls).
Every time you see this pattern, you can use maplist/2. That is, the above is equivalent to:
ps(Ls) :- maplist(p, Ls).
The goal maplist(p, Ls) is true iff p holds for each element L of Ls.
Note that it will limit your understanding of Prolog if you think in terms of "looping" and "repeating". These are imperative notions and only make sense when the list is already fully instantiated. However, from Prolog, we expect more than that: We expect a full-fledged relation to also generate lists for which the relation holds. And in such cases, there is nothing to "repeat" yet: We start from nothing, and ask Prolog what solutions there are in general.
Thus, think in terms of describing when the relation ps/1 holds for lists of lists:
It holds for the empty list [].
It holds for the list [L|Ls] if our initial predicate (p/1) holds for L, and ps/1 holds for the remaining list Ls.
This declarative reading is applicable in all directions, no matter how many list elements are already instantiated, if any. It works for 10 lists just as well as for zero and 50.
I'm new to Prolog, trying to sum up only the first elements of each list.
takeFirst([[1,2,3],[4,5,6],[7,8,9]],R). --> R=1+4+7=12
It keeps outputting false and I don't understand what I'm missing here.
takeFirst([HF|_],[],HF):-!.
takeFirst([H|L1],R):- H=[_|_], L1=[_|_],!,takeFirst(H,L1,NN), R is NN.
takeFirst([HF|_],[K|L2],HF):- takeFirst(K,L2,NN), HF is HF+NN.
does anyone see what is wrong here?
Well your code is rather chaotic: you define a takeFirst/3 first (that probably should be the base case?). Next you define two recursive cases, but you somehow pass the head the list in the recursive call, etc.
Actually the problem is easy to solve. You first better redirect your takeFirst/2 to a takeFirst/3` with an accumulator:
takeFirst(L,R) :-
takeFirst(L,0,R).
Next we consider a base case: we reached the end of the list:
takeFirst([],R,R).
In this case we reached the end, and so the value of the accumulator, the variable we pass that keeps track of the sum thus far, is returned as the result.
In the recursive case, we are given a list [H|T] and we are interested in the head of the head HH so [[HH|_]|T]. In that case we add HH to the accumulator and do a recursive call with T:
takeFirst([[HH|_]|T],Ra,R) :-
Rb is Ra+HH,
takeFirst(T,Rb,R).
So putting it together we get:
takeFirst(L,R) :-
takeFirst(L,0,R).
takeFirst([],R,R).
takeFirst([[HH|_]|T],Ra,R) :-
Rb is Ra+HH,
takeFirst(T,Rb,R).
Something that was not very clear in your question is what should be done if there is an empty list in your list, like [[1,2,3],[],[7,8,9]]. The above predicate will fail: it expects that all lists have at least one element. In case you simply want to ignore these lists, you can alter your code into:
takeFirst2(L,R) :-
takeFirst2(L,0,R).
takeFirst2([],R,R).
takeFirst2([[]|T],Ra,R) :-
takeFirst2(T,Ra,R).
takeFirst2([[HH|_]|T],Ra,R) :-
Rb is Ra+HH,
takeFirst2(T,Rb,R).
So we add a case where the list follows the pattern [[]|T], in which case we simply perform a recursive call with the tail T.
Based on the given above predicates, constructing a list of heads is not hard as well:
heads([],[])
heads([[HH|_]|TA],[HH|TB]) :-
heads(TA,TB).
I want to define predicate which takes a list, adds an element to the list, let's say the number "1", and then returns the list.
I've found out I can add elements to a list using append/3, but I want to use in inside another predicate, thus why I want it to return "my modified list".
My object-oriented mindset tells me to ask the interpreter something like: ?-append(X,5,X). , so that it takes the list X, adds 5 to it, and returns "the new X", but I know that's not how unification works, so my mind is kinda in a glitch.
Can anyone please try to explain how something like this could be achievable?
You are already very close to the solution, so I only rephrase what you are beginning to sense already:
First, you cannot modify a list in pure Prolog.
Instead, you should think in terms of relations between entities. In your case, think in terms of relations between lists.
So, "adding the number 1" to a list is a relation between two lists, which could look like this:
list_with_one(Ls, [1|Ls]).
Note that this works in all directions! You can use it to:
generate answers
test particular cases
"reverse" the direction etc.
So, all you need to do in your case is to think in terms of relations between lists: One without an element, and how this relates to a different list with the element.
Obviously, these two lists will be indicated by different variables and different arguments.
Note in particular that append(X, 5, X) cannot hold: First of all, append/3 is meant to be a relation between lists, and 5 is not a list. Second, assuming you wrote for example append(Xs, [5], Xs), then this would be true if there where a list Xs such that if the element 5 were appended to Xs, the resulting list would again be Xs. Good luck finding such a list... Note also the naming convention to denote lists by letting the variable name end with an s.
It is also falls a bit short to blame this on your "object-oriented mindset", since you can have object oriented programming in Prolog too.
Although lists in Prolog cannot be modified, it is possible to add elements to the end of a list with an unspecified length. In this way, items can be "appended" to a list without creating another list:
:- initialization(main).
append_to_list(List,Item) :-
append_to_list(List,Item,0).
append_to_list(List,Item,Index) :-
% using SWI-Prolog's nth0 predicate
(nth0(Index,List,Check_Item),
var(Check_Item),
nth0(Index,List,Item));
(Next_Index is Index+1,
append_to_list(List,Item,Next_Index)).
main :-
A = [1,2,3|_],
append_to_list(A,4),
append_to_list(A,7),
writeln(A).
In this example, A becomes [1,2,3,4,7|_].
Using prolog, I have to create a rule that determines, when given a list, if the first element of the list is equal to the last element of the list. Below is my thinking.
The Base Cases:
1) If The Parameter Is Not A List: Return False
2) If The Parameter Is A List But Empty: Return False
3) If The Parameter Is A List But Has One Element: Return False
The Recursive Step:
Recursively Going Through The List Getting The
First Element And TheLast Element Then Compare
fela() :- false. <-- Base Case One
fela([]):-false. <-- Base Case Two
fela([H]):-false. <-- Base Case Three
fela([H|T]):- H1 is H, H1 == T, fela(T,H1). <-- Recursive Step
Bellow Are Function For First, Last, Member
first(F, [F|_]).
last(L, [H|T]) :- last(L, T).
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
I am having trouble with my recursive step, I am unsure of how to store the first element, and traverse the list and obtain the last element, then compare the results for a true/false answer. Could someone help me out
Thanks,
Erik :)
Here's an easy one:
fela(L) :- first(E, L), last(E, L).
Stare at that for a minute and let it really sink in.
Actually, it would be right, but your last/2 isn't, simply traversing the list with no base case that will ever succeed. A correct last/2 would look like this:
last(L, [L]).
last(E, [_|L]) :- last(E, L).
I see a lot of confused ideas in your case analysis. For one thing, in Prolog, you don't explicitly return true and false. You simply match what you match and the rest is failure. When dealing with lists, you automatically inherit the base case of the empty list and the inductive case of an element and the remainder of the list. This isn't sufficient to implement fela/1 from scratch because you have no way of remembering what your first element was. So if you want to build it from scratch you'll need a helper predicate so you can keep passing the first element along. It's going to look like this:
fela([H|T]) :- fela(H, T).
fela(First, [First]).
fela(First, [_|Xs]) :- fela(First, Xs).
Notice that we've preserved the analysis of one base case, one inductive case for handling the list. This is the usual situation when processing a recursive data structure. first/2 is a good example of when you don't follow the rule, because you aren't interested in one of the cases. Building the predicate out of first/2 and last/2 lets you escape the case analysis problem altogether, and is (in my opinion) more often what happens in practice.
Now I want to single out some of your ideas here for further comment. First, H1 is H is definitely not what you want. is/2 is exclusively for reducing arithmetic expressions. You will always have a variable on the left and an expression on the right, or it isn't meaningful. You're trying to do some kind of assignment here, but even H1 = H is not helpful here, because while Prolog has variables, it does not have assignables.
H1 is H, H1 == T says, implausibly, that H is both the head of the list and equivalent to the tail. This isn't ever really possible, because the tail is a list and the head is an element. Even if you could craft a situation where that were true, it definitely wouldn't be interesting to this predicate. Your recursive step here is really strange.
Another problem with your case analysis, case #3 should be true. With [X], X is both the first and the last element of the list, so fela/1 should be trivially true for all one-element lists.
I would advocate additional study. I think you have some odd notions that a little more reading might correct.
Can someone help me find the error in these rules?
concat([], List, List).
concat([Head|[]], List, [Head|List]).
concat([Head|Tail], List, Concat) :- concat(Tail, List, C), concat(Head, C, Concat).
Trying to concatenate two lists fails:
| ?- concat([1,2], [4,7,0], What).
no
To fix your code, the way you intended it, you just need to transform Head into [Head] in your last call to concat/3 in your last clause. The problem was that you called your predicate with Head only as first argument, which is not a list.
Though, here are several notes :
[Head|[]] is equivalent to [Head]
your algorithm has a poor complexity, n! I believe.
with no cut inserted after your second clause, you generate infinite choice points through the call of your third clause with a list of length 1 (that hence calls your second clause, that then is ran through your third clause, etc... infinite loop).
Here is SWI-pl's version, to hint you towards good prolog recursion :
append([], List, List).
append([Head|Tail], List, [Head|Rest]) :-
append(Tail, List, Rest).
You can find other resources on recent posts here or in Learn Prolog Now! tutorial if you want to learn how to use recursion properly.
It can be done by using append.
concatenate(List1, List2, Result):-
append(List1, List2, Result).
Hope this helps.
Here is the concatenation between two lists rule:
concat([],L2,L2). concat([Head|Tail],L2,[Head|L3]) :- concat(Tail,L2,L3).
The implementation is very simple.
concatenation is nothing but appending the second list at the end of the first list.
Keep on adding until the first list runs out of elements. Now add the second list to it.
ap([],L,L).
ap([H|T],L,[H|Z]):- ap(T,L,Z).
OUTPUT
?-ap([1,2,3],[a,b,c],List).
List=[1,2,3,a,b,c]
?-ap([1,2,3],[a,b],List).
List=[1,2,3,a,b]
?-ap([1,2],[a,b,c],List).
List([1,2,a,b,c])
?-ap([],[],List).
List=[]