I want to write a prolog program that checks if a list is included in other list.
Multiple elements matter
This is what I wrote but it fails for the input - inclusion([a,b,b,d],[a,b,b,c,c,d,d]).This should return true. other examples - inclusion([a, b, b, b, d], [a, b, b, c, c, d, d])
should return false.
inclusion([],_).
inclusion([X|L],Set):-
member(X,Set),delete(Set,X,Set2), inclusion(L,Set2).
Above is the code that I wrote. The logic was check if the first element is in Set.
Then delete that element from the set and check if the remaining list is in the Set.
But this doesn't seem to work
This predicate does not work with entries in the first list that appear multiple times, because delete removes all appearances of Set. Use select to remove only the first element that matches:
inclusion([],_).
inclusion([X|L],Set):-
member(X,Set),select(X, Set, Set2), inclusion(L,Set2).
Gives you:
?- inclusion([a,b,b,d],[a,b,b,c,c,d,d]).
true .
?- inclusion([a,b,b,b,d],[a,b,b,c,c,d,d]).
false.
inclus([],[]).
inclus([],[_|_]).
inclus([H1|T1],[H1|T2]) :- inclus(T1,T2).
inclus([H1|T1],[H2|T2]) :- \=(H1,H2),inclus([H1|T1],T2).
Note: the other answer defining the inclusion/3predicate will return true for the following goal:
?- inclusion([b, c, a],[a,b,c]).
true
I dont think this is what you want.
Related
I m studying Prolog and i see this code
foo([],[]).
foo([[A,_ ]|L], [A|P]) :-foo(L ,P).
The result say that this code take N element of list of list,
Ad example if we give this query:
?foo([[car],[house],[man]],X)
X= [c,h,m]
At first read i see that something wrong.
For me this code take the tail of list of list and the rest of first element of the list , so for me first expansion will be (trace)
foo([[house],[man]], ar)
foo([[man]], ouse)
foo([], an)
false.
I try to compile with swi-prolog and give this trace:
[trace] ?- trace,foo([[car],[house],[man]],X).
Call: (9) foo([[car], [house], [man]], _1016) ? creep
Fail: (9) foo([[car], [house], [man]], _1016) ? creep
false.
What are I wrong?
Obtaining the first elements
The pattern [A, _] in your clause is wrong, or at at least not generic enough. [A, _] unifies with a list that contains exactly two elements, but this will thus fail for lists with more than two elements, or with one elements, like you found out.
You need to use the [A|_] pattern: indeed a list where the head is A, and we are not interested in the rest (tail). like:
foo([],[]).
foo([[A|_]|L], [A|P]) :- foo(L, P).
That being said, you can simplify this, by implementing a predicate that takes the head of a list:
head([H|_], H).
and then make use of maplist/3 [swi-doc]:
foo(A, B) :-
maplist(head, A, B).
maplist will thus call head like head(Ai, Bi), with Ai and Bi elements of A and B respectively.
Obtaining a substring with the first character
but based on the sample output, this is not what you want: you also want to obtain the first "character" of the atom, we can do that by using string_chars/2 [swi-doc]:
head_first([A|_], C) :-
string_chars(A, [C|_]).
and then define foo/2 again with maplist/3 [swi-doc]:
foo(A, B) :-
maplist(head_first, A, B).
we then obtain:
?- foo([[car],[house],[man]], X).
X = [c, h, m].
The following code works, but I have certain doubts as to how it does things under the hood. For example, on the first call to Exit(9) I don't understand how c is moved to the variable O. Is this part of the unification process or something else entirely? Care anyone to explain?
concat([], List, List).
concat([Head|[]], List, [Head|List]).
concat([Head|Tail], List, Concat) :- concat(Tail, List, C), concat([Head], C, Concat).
You can do 'by hand' the unification process, to verify that the trace line labelled Exit:(9) actually 'cons-ed' [c] to [x,y,z]:
?- [Head|[]]=[c],List=[x,y,z],[Head|List]=O.
Head = c,
List = [x, y, z],
O = [c, x, y, z].
but, you cannot claim it works:
?- concat([a,b,c],[x,y,z],L).
L = [a, b, c, x, y, z] ;
L = [a, b, c, x, y, z] ;
...
it doesn't terminate, and this clearly indicate some problem. The second clause is redundant - both in behaviour and syntax. It would be usually written like
concat([Head], List, [Head|List]).
since the empty tail list it's implicitly present in every list - except where a tail is explicitly indicated:
?- [Head|[]]=[X].
Head = X.
About the behaviour, you can see from your trace that it's the first clause that is never used. So, you can think it's the first that is redundant - maybe you added the second because of the last call of the third clause, where a 'singleton' list is required (I mean ...,concat([Head], C, Concat).). But such call it's causing the non termination issue. Better to simplify the whole program, removing the second clause and simplifying the third....
What I basically want to achieve is, that given a list of lists A, I want a predicate that checks if the elements of a list B are exactly contained in list A.
So for example:
A = [[1,2],[3,4],[5],[]]
B = [1,2,3,4,5]
and
A = [[1,2],[3,4],[5],[]]
B = [2,5,3,4,1]
Would result to true, but
A = [[1,2],[3,4],[5],[]]
B = [1,2,3,4]
and
A = [[1,2],[3,4],[5],[]]
B = [1,2,3,4,5,6]
would both result to false.
is this possible in prolog?
Exactly means:
Order doesn't matter, it just has to contain all the elements.
Also, imagine that the B list doesn't contain duplicates.
So if A would contain duplicates, we should get false as a result.
The trivial answer:
?- flatten([[1,2],[3,4],[5],[]], [1,2,3,4,5]).
true.
?- flatten([[1,2],[3,4],[5],[]], [1,2,3,4]).
false.
?- flatten([[1,2],[3,4],[5],[]], [1,2,3,4,5,6]).
false.
Or,
foo(A, B) :- % because I don't know how to call it
flatten(A, B).
If you are talking about sets:
bar(A, B) :-
flatten(A, A_flat),
sort(A_flat, A_sorted),
sort(B, A_sorted).
You can use msort/2 if you don't want to remove duplicates.
If the question is, "how do I implement flatten/2", you can find several answers on SO.
I'm trying to make a Prolog predicate iscontained/2: iscontained(List, Search) where it returns true. if the Search is listed within the given List, false. if not. And if it is a variable that is inputted, then it just returns that it equals each element in the list.
Example:
?- iscontained([a, b, c], a).
true.
?- iscontained([a, b, c], d).
false.
?- iscontained([a, b, c], A).
A = a;
A = b;
A = c;
false.
I need a shove in the right direction, not asking for a hand out, unless you know a quick way to do it. Any help is appreciated, thanks.
Please note that the frequently proposed member/2 predicate admits solutions that are no lists at all:
?- member(e,[e|nonlist]).
true.
This is not a big problem in many situations, but should be mentioned nevertheless.
A natural, symmetric definition that only admits lists uses DCGs:
... --> [] | [_], ... .
iscontained(Es, E) :-
phrase((...,[E],...), Es).
The ... is a non-terminal which denotes an arbitrary sequence.
While this is entirely overkill for this tiny example, it gives you a template for more interesting patterns. Like
iscontainedtwice(Es, E) :-
phrase((...,[E],...,[E],...), Es).
You will need to consider two cases. I'll leave the body of the rules up to you.
iscontained([A|Xs],A)
iscontained([X|Xs],A)
[edited to remove reference to the empty list: the empty list contains nothing: if encountered, the predicate fails.]
Now that you certainly already came up with a solution, I'd like to mention one thing:
The classical version:
member(Item, [Item|_List]).
member(Item, [_Head|List]) :- member(Item, List).
leaves a choice point after having found the last element possible, ie:
?- member(A, [1, 2, 3]).
A = 1;
A = 2;
A = 3;
false.
while
member2(Item, [Head|List]) :-
member2(List, Item, Head).
member2(_List, Item, Item).
member2([Head|List], Item, _PreviousHead) :-
member2(List, Item, Head).
treats the empty list at the same time as the last element and allows optimization:
?- member2(A, [1, 2, 3]).
A = 1;
A = 2;
A = 3.
That's the version used in SWI-Prolog (and certainly Jekejeke Prolog and maybe others). Its author is Gertjan van Noord.
That's just meant as a reminder that, while the exercise of coming up yourself with a member/2 implementation is excellent, it should not lead you not use the built-ins afterwards, they're often fine tuned and more efficient!
I want a function that will take two lists A and B and return lists Aout and Bout, such that elements from the beginning of A up to a given element (say the atom 'a') have been removed and appended to the end of B, discarding the character. My attempt below:
% usage: take_while(A, Aout, B, Bout)
take_while([], [], B, B).
take_while(['a'|As], As, B, B).
take_while([A|As], As, B, Bout) :-
append(B, [A], Bout),
%take_while(???
The last clause might be the wrong approach. How do I do this?
Looks like you need to simply add the call to take_while to that last clause: (Actually, I am not sure why the second parameter is needed so I'm removing it from this answer).
take_while([], [], B, B).
take_while(['a'|As], As, B, B).
take_while([A|As], ARem, B, Bout) :-
append(B, [A], BTemp), take_while(As, ARem, BTemp, Bout).