Creating sub-list from list in Prolog - list

I am having trouble understanding a concept in prolog.
I have a prolog list:
MyList = [item(dog,red), item(cat,black), item(rat,gray)]
and I am looking to create a list of just the colors i.e.
[red,black,gray]
Currently the solution I have tried is:
getlistcolors([item(_,C)|T], Result) :-
getlistcolors(T,Result),
append([C],Result,Result).
getlistcolors([],_).
I would like to be able to call the function:
?- getlistcolors(MyList, Result).
Result = [red,black,gray]
Any help is appreciated.
Thanks

Try with
getlistcolors([], []).
getlistcolors([item(_,C)|T], [C | Result]) :-
getlistcolors(T,Result).
You can't append the new find C color with
append([C],Result,Result)
because you're imposign that the second list and the appended list are equals.
You should use two different variables writing
getlistcolors([item(_,C)|T], Result) :-
getlistcolors(T,HeadC),
append([C],HeadC,Result).
but you can obtain the prepend-C effect simply translating C as head of the second argument
getlistcolors([item(_,C)|T], [C | Result]) :-
Second point wrong with your code: the terminal clause can't be written as
getlistcolors([], _).
or the second argument isn't unified with [] and the reasult become something like
[red,black,gray|_20]
where _20 is a variable that isn't unified.

Just to fix a problem in lurker comment:
when using setof/3 or bagof/3, you have to specify 'universal quantification' of each variable involved in the query, you're not interested in:
?- MyList = [item(dog,red), item(cat,black), item(rat,gray)],setof(Color, P^member(item(P, Color), MyList), ColorList).
MyList = [item(dog, red), item(cat, black), item(rat, gray)],
ColorList = [black, gray, red].
the missing quantification problem is better explained in the bagof section of inline documentation
A SWI-Prolog solution could make use of libraries yall and apply (both autoloaded, you don't have to worry about including them):
getlistcolors(List, Colors) :- maplist([E,C]>>(E = item(_,C)), List, Colors).
?- getlistcolors([item(dog,red), item(cat,black), item(rat,gray)],Cs).
Cs = [red, black, gray].

Related

Prolog - Merging 2 lists gives me a list of lists instead of a single list

I have tried many solutions and this is as close as I have come to the result I am expecting.
I want to combine 2 lists, but i am getting a list of lists rather than one list.
res1(Title,L3) :- findall(Genre,(book(Title,_,Genre,_)),L3).
res2(Author,L2) :- findall(Genre,(name(Author,Editor,_), house(Editor,_,Genre)),L2).
finalres(Title,Author,L) :- res1(Title,L3), res2(Author,L2), merged(L3, L2, L).
merged([],List,List).
merged([Element|List1],List2,[Element|List3]) :- merged(List1,List2,List3).
The merged code comes from Prolog Combining Two Lists.
When I attempt this by writing two lists in arguments, i get the proper result:
?- merged([g1,g2],[g3,g4],L).
L = [g1, g2, g3, g4].
However when I call it through my finalres, I get the following:
?- finalres("some title",a1,L).
L = [[g3, g4], [g1, g2]]
I would like to see L = [g3, g4, g1, g2]- the order does not bother me.
I also don't need to remove dupes from list (I'll deal with member later :) )
Is it because the second argument of merged (List2) is never separated? Am i misunderstanding how this append code works?
Using SWI-Prolog.
Thanks in advance!
fixed using the suggested answer in comments:
finalres(Title,Author,K) :- res1(Title,L3),
res2(Author,L2),
merged(L3, L2, L),
flatten(L, K).

Prolog answers Argument = Argument, instead of answer No

How can I make prolog answer No , if search_answer didn't find an answer , and
Yes with L = [Answer]
search_answer : predicate that returns a list or let's A as a free variable.
found_list(L) :-
search_answer(L).
For example , when asked found_list(L) , although search_answer didn't find an answer , Prolog still answers Yes. I print L , and it is equal to _496 , a free variable.
Given the above piece of code, found_list answers L = [...] if search_answer found a list , else returns L = L, while I want to answer no
I tried the following , but doesn't work
found_list(L) :-
search_answer(L) , is_list(L).
liar_detector is my search_answer predicate , with L = answer
and liars is my found_answer
In found_list(L) :- search_answer(A). both L and A are singleton. I assume you saw the warning. You need to fix that for this predicate to make sense. Do you really want L = [Answer] or L = Answer?
You can achieve what you're after this way:
found_list(A) :-
search_answer(A).
This will fail (result in "no") if search_answer(A) doesn't succeed, and your result will be A if it does succeed.
If you want the result as an answer within a list, you can do this:
found_list([A]) :-
search_answer(A).
I'm not sure what the value is of either of these. The first found_list/1 is just a simple wrapper on search_answer/1 without any additional logic. The second simply makes a single-element list out of the search_answer/1 result. If A is already a list, you don't need to put it inside of brackets ([...]), otherwise you just get a list within a list. I suspect you are really trying to do something else but haven't explained.
In response to the updated question, the following code should work if A is a simple unbound term:
found_list(A) :-
search_answer(A),
is_list(A).
However, is_list/1 will succeed if its argument has a list structure even though it's elements may be unbound:
| ?- X = [_], is_list(X).
X = [_]
yes
| ?-
So, for example, if search_answer(A) succeeds with A = [_], then found_list(A) will suceed with A = [_].
ground/1 can be useful here since:
| ?- ground(X).
no
| ?- ground([_|_]).
no
| ?- ground([a,b]).
yes
| ?-
Thus, the following solution should work:
found_list(A) :-
search_answer(A),
ground(A).
If your intention is not to backtrack to search_answer(A) if A is not ground, but just fail, you could implement found_list/1 as:
found_list(A) :-
search_answer(A),
( ground(A) -> true ; !, false ).
I think, though, there may be a more fundamental issue with the code, as it shouldn't have a behavior that you feel compelled to work around like this.

Inserting value into the begining of each sublist

I'm currently writing a predicate that will run through a list of lists and insert a value I have calculated onto the beginning of the list
Step one is easy, just perform the calculation for each list and unify variable N with it.
checkthrough([]).
checkthrough([H|T]):-
count_validentries(H,N),
checkthrough(T).
What I'm trying to achieve now is to put that variable N onto the beginning of each of my sublists, so each list begins with the count of valid entries.
I have attempted to do this using an accumulator. Attempting to start with an empty list, and to every time add the new value N and the head of the list to it:
checkthrough([],Sofar,Lastone).
checkthrough([H|T],Sofar,Lastone):-
count_validentries(H,N),
Newsofar is [N,H|Sofar],
checkthrough(T,Newsofar,Lastone).
I'm quite sure I'm making a really stupid mistake somewhere along the lines. This is not valid Prolog syntax, failing with Arithmetic:' [2 internal variables]' is not a function.
Does anyone have any tips please?
Using meta-predicate maplist/3 and Prolog lambda simply write:
?- use_module(library(lambda)).
?- maplist(\Es^[N|Es]^count_validentries(Es,N), Ess, Xss).
Also, I'd guess that you're really looking for (-)/2 pairs which is how key-value pairs are commonly represented—by library predicates and the built-in predicate keysort/2. Consider:
?- Ess = [[a,b,c],[d,e],[],[f]],
maplist(\Es^(N-Es)^length(Es,N), Ess, Xss),
keysort(Xss, Yss).
Ess = [ [a,b,c], [d,e], [], [f]],
Xss = [3-[a,b,c], 2-[d,e], 0-[], 1-[f]],
Yss = [0-[], 1-[f], 2-[d,e], 3-[a,b,c]].
Maybe
checkthrough([],Sofar,Sofar).
checkthrough([H|T],Sofar,Lastone):-
count_validentries(H,N),
checkthrough(T,[[N|H]|Sofar],Lastone).
but you'll end up with the list reversed. Keeping it simpler will help
checkthrough([],[]).
checkthrough([H|T],[[N|H]|Rest]):-
count_validentries(H,N),
checkthrough(T,Rest).
or better, if you're running a recent version of SWI-Prolog:
checkthrough(L,L1) :-
maplist([E,E1]>>(count_validentries(E,N),E1=[N|E]), L,L1).

Removing heads from lists in Prolog

I'm trying to write a predicate to remove the head from every list in list of lists and add the tails to a new list. The resulting list should be returned as the second parameter.
Here's the attempt:
construct_new(S,New) :-
New = [],
new_situation(S,New).
new_situation([],_).
new_situation([H|T], New) :-
chop(H, H1),
new_situation(T, [H1|New]).
chop([_|T], T).
You would call it like this:
construct_new([[x,x],[b,c],[d,e,f]],S).
This, however, only produces output true..
Step-by-step execution
Your query is construct_new(Input,Output), for some instanciated Input list.
The first statement in construct_new/2 unifies Output (a.k.a. New) with the empty list. Where is the returned list supposed to be available for the caller? Both arguments are now unified.
You call new_situation(Input,[])
You match the second clause new_situation([H|T],[]), which performs its task recursively (step 4, ...), until ...
You reach new_situation([],_), which successfully discards the intermediate list you built.
Solutions
Write a simple recursive predicate:
new_situation([],[]).
new_situation([[_|L]|T],[L|R]) :-
new_situation(T,R).
Use maplist:
construct_new(S,R) :-
maplist(chop,S,R).
Remark
As pointed out by other answers and comments, your predicates are badly named. construct_new is not a relation, but an action, and could be used to represent almost anything. I tend to like chop because it clearly conveys the act of beheading, but this is not an appropriate name for a relation. repeat's list_head_tail(L,H,T) is declarative and associates variables to their roles. When using maplist, the other predicate (new_situation) doesn't even need to exist...
...even though guillotine/3 is tempting.
This could be done with a DCG:
owth(Lists, Tails) :-
phrase(tails(Tails), Lists).
tails([]) --> [].
tails([T|Tails]) --> [[_|T]], tails(Tails).
Yielding these queries:
| ?- owth([[x,x],[b,c],[d,e,f]], T).
T = [[x],[c],[e,f]] ? ;
no
| ?- owth(L, [[x],[c],[e,f]]).
L = [[_,x],[_,c],[_,e,f]]
yes
(owth = Off with their heads! or, if used the other direction, On with their heads!)
If you also want to capture the heads, you can enhance it as follows:
owth(Lists, Heads, Tails) :-
phrase(tails(Heads, Tails), Lists).
tails([], []) --> [].
tails([H|Hs], [T|Tails]) --> [[H|T]], tails(Hs, Tails).
We use meta-predicate maplist/[3-4] with one of these following auxiliary predicates:
list_tail([_|Xs],Xs).
list_head_tail([X|Xs],X,Xs).
Let's run some queries!
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],Heads,Tails).
Heads = [x,b,d],
Tails = [[x],[c],[e,f]].
If you are only interested in the tails, use maplist/4 together with list_head_tail/3 ...
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],_,Tails).
Tails = [[x],[c],[e,f]].
... or, even simpler, maplist/3 in tandem with list_tail/2:
?- maplist(list_tail,[[x,x],[b,c],[d,e,f]],Tails).
Tails = [[x],[c],[e,f]].
You can also use the somewhat ugly one-liner with findall/3:
?- L = [[x,x],[b,c],[d,e,f]],
findall(T, ( member(M, L), append([_], T, M) ), R).
R = [[x], [c], [e, f]].
(OK, technically a two-liner. Either way, you don't even need to define a helper predicate.)
But definitely prefer the maplist solution that uses chop as shown above.
If you do the maplist expansion by hand, and name your chop/2 a bit better, you would get:
lists_tails([], []).
lists_tails([X|Xs], [T|Ts]) :-
list_tail(X, T),
lists_tails(Xs, Ts).
And since you can do unification in the head of the predicate, you can transform this to:
lists_tails([], []).
lists_tails([[_|T]|Xs], [T|Ts]) :-
lists_tails(Xs, Ts).
But this is identical to what you have in the other answer.
Exercise: why can't we say:
?- maplist(append([_]), R, [[x,x],[b,c],[d,e,f]]).

Prolog - copy a piece of list

I need to duplicate list in prolog.
I have list:
L = [a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)].
Output will be: L = [string1, string2, string3, string4].
How can I do this?
I can copy whole list by code:
copy([],[]).
copy([H|L1],[H|L2]) :- copy(L1,L2).
I have tried something like:
copy2([],[]).
copy2([H|L1],[K|L2]) :- member(f(K,_),H), copy2(L1,L2).
But it does not work properly.
But I need only strings from my original list. Can anyone help?
pattern matching is used to decompose arguments: you can do
copy([],[]).
copy([a(H,_)|L1],[H|L2]) :- copy(L1,L2).
It is uncommon to use a structure a/2 for this purpose. More frequently, (-)/2 is used for this. Key-Value is called a (key-value) pair.
Also the name itself is not very self-revealing. This is no copy at all. Instead, start with a name for the first argument, and then a name for the second. Lets try: list_list/2. The name is a bit too general, so maybe apairs_keys/2.
?- apairs_keys([a(string1,value1),a(string2,value2)], [string1, string2]).
Here are some definitions for that:
apairs_keys([], []).
apairs_keys([a(K,_)|As], [K|Ks]) :-
apairs_keys(As, Ks).
Or, rather using maplist:
apair_key(a(K,_),K).
?- maplist(apair_key, As, Ks).
Or, using lambdas:
?- maplist(\a(K,_)^K^true, As, Ks).
Declarative debugging techniques
Maybe you also want to understand how you can quite rapidly localize the error in your original program. For this purpose, start with the problematic program and query:
copy2([],[]).
copy2([H|L1],[K|L2]) :-
member(f(K,_),H),
copy2(L1,L2).
?- copy2([a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)], [string1, string2, string3, string4]).
false.
Now, generalize the query. That is, replace terms by fresh new variables:
?- copy2([a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)], [A, B, C, D]).
false.
?- copy2([a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)], L).
false.
?- copy2([a(string1,value1),B,C,D], L).
false.
?- copy2([a(string1,value1)|J], L).
false.
?- copy2([a(S,V)|J], L).
false.
?- copy2([A|J], L).
A = [f(_A,_B)|_C], L = [_A|_D]
; ... .
So we hit bottom... It seems Prolog does not like a term a/2 as first argument.
Now, add
:- op(950,fx, *).
*_.
to your program. It is kind of a simplistic debugger. And generalize the program:
copy2([],[]).
copy2([H|L1],[K|L2]) :-
member(f(K,_),H),
* copy2(L1,L2).
Member only succeeds with H being of the form [_|_]. But we expect it to be a(_,_).