Related
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].
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).
I have more possible list as goal,but i need only one longest list.Is this possible to get first longest list?
li-->[a]|[b]|[c].
int-->['1']|['2']|['3'].
num-->int,num_nl.
num_nl-->num|[].
list1-->num,li.
classify(L,S,R):-list1(S,[]),extract(S,L,R).
extract(S,L1,L2):-append(L11,L22,L1),append(S,L3,L22),append(L11,L3,L2).
Here ERROR: Out of local stack.I want only longest list as goal:
?-classify([c,'1','1',a,f],S,R).
S = ['1', '1', a], R = [c, f] ;
false.
?-classify([c,'1','2','3',a,f,'1','1','2','3',b],S,R).
S = ['1','2','3',a], R = [c, f,'1','1','2','3',b] ;
false.`
You don't provide any detail on how classify/1 is implemented; it could be that you can define it so that it only gives you the longest list.
Your other option is to collect all results, using either findall/3 or bagof/3 or setof/3, then make pairs with the list length as the first element, then sort these pairs and pick the last.
For example:
?- bagof(X, classify(X), Xs),
maplist(length, X, Lengths),
pairs_keys_values(Ps, Lengths, Xs),
keysort(Ps, Sorted),
last(_-Longest, Sorted).
It uses pairs_keys_values/3 and last/2 as defined in the SWI-Prolog standard libraries.
This approach will work, even though it has several problems. It is difficult to discuss those without any knowledge of what classify/1 does.
I used at least once a convoluted variant of Boris' answer
?- R=[_-S|_],setof(L-X,T^(classify(X),length(X,T),L is -1*T),R).
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]]).
I want to solve the following exercise in Prolog:
For a list of integers Zs, max_sequence(Zs,Xs) finds a longest increasing subsequence Xs.
Sample queries:
?- max_sequence([1,2,1,2,3,4,2,1,2,1],Xs).
Xs = [1,2,3,4]. % expected result
?- max_sequence([1,2,1,2,3,4,2,1,6,7,7,2,1,8],Xs).
Xs = [1,2,3,4,6,7,8]. % expected result
I can't understand why... but my code is wrong, the result is always false.
max_sequence(L,R) :-
cresc(L,[],R).
cresc([],[],[]).
cresc([H|T],C,[H|C]) :-
maxList(H,C),
\+ member(H,C),
cresc(T,C,C).
cresc([H|T],C,C) :-
member(H,C),
cresc(T,C,C).
cresc([H|T],C,C) :-
\+ maxList(H,C),
cresc(T,C,C).
maxList(_,[]).
maxList(N, [H|T]) :-
N>H,
maxList(N,T).
I would like to know if my approach to the problem is correct.
Thanks for any help!
TL;DR: Solve problems on a high-level: Think idiomatically; and don't reinvent the wheel :)
Use clpfd!
:- use_module(library(clpfd)).
We proceed by taking the following two steps:
We start by using the meta-predicate splitlistIfAdj/3 together with (#>=)/3:
?- splitlistIfAdj(#>=,[1,2,2,2,1,2,3,4,2,1,3,5,7,1],Zss).
Zss = [[1,2],[2],[2],[1,2,3,4],[2],[1,3,5,7],[1]].
We are only interested in sublists of maximum size. max_of_by/3 can exclude all other ones:
?- max_of_by(Xs,[[1,2],[2],[2],[1,2,3,4],[2],[1,3,5,7],[1]],length).
Xs = [1,2,3,4]
; Xs = [1,3,5,7].
That's it! Let's put it together and define list_longest_ascending_sublist/2:
list_longest_ascending_sublist(Xs,Zs) :-
splitlistAdjIf(#>=,Xs,Yss),
max_of_by(Zs,Yss,length).
Sample queries:
?- list_longest_ascending_sublist([1,2,2,2,1,2,3,4,2,1,3,5,7,1],Zs).
Zs = [1,2,3,4]
; Zs = [1,3,5,7].
?- list_longest_ascending_sublist([1,2,2,3,4,5,6,2,1,2,3,4,2,1,3,5,7,1],Zs).
Zs = [2,3,4,5,6].
I can't understand your approach at all, but using Trace command in swi-prolog you can see your program execution step by step to see where it fails. Try it and you will see what's wrong with your code.
Anyway this could be one possible solution: starting from the first element of the list you should simply collect a list until elements are increasing, keeping also the length of this sublist, this is the first candidate. Then start again collecting a new list and its length, and if is longer than the candidate, you switch them, and so on..
Here you can find the code: max_seqs , the first part.