Removing heads from lists in Prolog - list

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]]).

Related

Get "real" prefixes/suffixes/infixes in Prolog

the Prolog notation of prefix/suffix is a quite easy one:
It pretty much puts all the work on append.
For those who don't know:
prefix(P,L):-append(P,_,L).
suffix(S,L):-append(_,S,L).
Now this means, that the result for prefix(X,[a,b,c,d]).
will be: X=[];X=[a];X=[a,b];X=[a,b,c];X=[a,b,c,d]
Here is my problem with this: I want a "real" prefix. Hence, a prefix cannot be empty, nor can the part following it be empty.
So the result to the query prefix(X,[a,b,c,d]). should be
X=[a];X=[a,b];X=[a,b,c]
and that's it.
Unfortunately, the real beaty of the standard-built in prefix predicate is, that it can use the termination of append, which is append([],Y,Y).
So it is pretty easy to know when to stop, picking the list apart one by one till the list is empty.
My termination means: Stop if there is exactly one element left in your list.
How do I do this?
My naive result would be:
prefix(P,L):-
length(P,1),append(P,E,L),E/=[].
This feels wrong though. I'm at work so I haven't checked if this actually works, but it should:
Is there any more convenient way to do this?
Same goes for suffix, which will be even harder since you do not have a way to adress the Tail as specific as the Head, I guess I'd just reverse the whole thing and then call prefix on it.
Infix will just be a combination of two.
I hope it is clear what I mean. Thanks for your input!
tl;dr: How to write a predicate prefix/2 which only filters real prefixes, so the prefix itself can not be empty, nor can the list followed by it be empty.
For the real prefix, you can try to do it like this:
list_prefix(List, [H|T]) :-
append([H|T], [_|_], List).
This just says that the first argument must have at least one element, and the rest of the list must have at least one element.
And following the suggestion by #false to make it more explicit:
list_real_prefix(List, Prefix) :-
Prefix = [_|_],
Rest = [_|_],
append(Prefix, Rest, List).
The "real" suffix will be exactly the same:
list_real_suffix(List, Suffix) :-
Front = [_|_],
Suffix = [_|_],
append(Front, Suffix, List).
You can also use a DCG for this, which is descriptive:
list_prefix(P) --> non_empty_seq(P), non_empty_seq(_).
non_empty_seq([X]) --> [X].
non_empty_seq([X|Xs]) --> [X], non_empty_seq(Xs).
| ?- phrase(list_pref(P), [a,b,c,d]).
P = [a] ? a
P = [a,b]
P = [a,b,c]
no
| ?-
You can define the suffix similarly:
list_suffix(S) --> non_empty_seq(_), non_empty_seq(S).

Creating a set from a list in Prolog

So basically my task is to create a Set out of a given List with a predicate containing 2 parameter.
The first one is the list and the second is the Set´s value.
However somehow it gives me a List which contains the Set as the Head and a Tail with a variable:
2 ?- list2set([2,3,4,4] , X).
X = [2, 3, 4|_G2840] .
thats the code:
list2set( [] , _).
list2set([ListH|ListT] , Set ) :- member(ListH, Set) , list2set(ListT , Set).
It seems to be a really basic mistake I made.
First, there are no sets in Prolog. We have only lists1. So what you can do is to relate a list with duplicate elements to a list without. list_nub/2 would be such a definition.
To your current definition:
Already list2set([], [a]) succeeds, which can't be right. So your definition is too general. You need to replace list2set([],_) by list2set([],[]).
Then, replace member(ListH, Set) by member(ListH,ListT).
And you need another rule for the case where the element is not present:
list2set([] , []).
list2set([E|Es] , Set ) :-
member(E, Es) ,
list2set(Es , Set).
list2set([E|Es] , [E|Set] ) :-
maplist(dif(E), Es),
list2set(Es , Set).
A more compact definition that avoids redundant answers is list_nub/2.
1) Strictly speaking, one could extend unification via attributed variables2 to implement ACI-unification to have real sets.
2) To my—rough—understanding this would require the implementation of attributed variables in SICStus. Other interfaces like the current in SWI or YAP are most probably insufficient ; as they already are for CLP(B). See this discussion for more.
Here is a definition that just uses member/2.
% base case
set([], []).
% here we say that if the head is in the tail of the list
% we discard the head and create a set with the tail
% the exclamation mark is a "cut" which means that if member(H, T) was true
% prolog cannot backtrack from set([H|T], X) to set([H|T], [H|X]).
% this prevents giving extra answers that aren't sets, try removing it.
set([H|T], X):- member(H, T), !, set(T, X).
% and here we say that if the previous clause didn't match because
% head is not a member of tail then we create a set of the tail adding head.
set([H|T], [H|X]):- set(T, X).
Hope it helps!
Nice way to populate a unique list, keeping it open-ended.
You can close it with a call length(Set, _), or a hand-coded equivalent (make it deterministic, too), when you're finished:
list2set([], S):-
% length( S, _), !
close_it(S). % use var/1
Also, consider calling memberchk/2 instead of member/2.
You could also give a "smart" answer, by defining
list2set(X, X).
and saying that you allow duplicates in your representation for sets.

Sublists in Prolog(without recognizing the empty list)

I want to create a predicate in Prolog which will check if a list A is a sublist of a list B. Moreover I do not want my program to consider an empty list as a subset of another one.
E.g. included_list([1,4],[1,2,3,4,5]).
true.
included_list([2,3],[1,2,3,4,5]).
true.
included_list([1,6],[1,2,3,4,5]).
false.
included_list([],[1,2,3,4,5]).
false.
and so on...
So, I have written the following code so far:
member(X,[X|Tail]).
member(X,[Head|Tail]):- member(X,Tail).
included_list([X],_).
included_list([Head|Tail],List):- member(Head,List), included_list(Tail,List).
But the above code seems to be wrong, because in one specific case it throws true, instead of throwing wrong. I wish I'd made it clear having presented the following screenshot:
As you might have noticed the fifth(5th) sentence gives true, instead of wrong. That is, when I write a sentence of the form:
included_list([x,y],[w,x,v,z]).
whereas only x is included in the second list(and not y) the program gives me true(and this is wrong).
In general, if the first argument of the first list is included in the second list then, no matter if the rest of the former are included in the latter, the program gives me true.
In any other case the program gives me the right result(true or false).
What do I do wrong?
I will be waiting for your answers!
Thank you in advance!
Your problem is the first clause of included_list/2. This:
included_list([X], _).
What does it mean? It means, "If the first argument is a list with one element, succeed, ignoring the second argument."
A short aside: if you would not ignore compiler warnings, you would have caught this mistake already. You should get a loud and clear "Singleton variable" warning, hinting that the code you have written does not do what you think it does.
What you actually mean is more along the lines of:
subset_list([X|Xs], Ys) :-
subset_list_1(Xs, X, Ys).
subset_list_1([], X, Ys) :-
member(X, Ys).
subset_list_1([X|Xs], X0, Ys) :-
member(X0, Ys),
subset_list_1(Xs, X, Ys).
But I don't know why you don't simply use the available subset/2, and simply add a requirement that the subset is not an empty list:
subset_list(Subset, List) :-
Subset = [_|_], % a list with at least one element
subset(Subset, List).
Despite what the documentation claims, the second argument to subset/2 does not have to be a true "set", but it does expect that both lists are ground (do not contain any free variables). You can see the source code here.
In this answer we let meta-predicate maplist/2 handle recursion and define:
all_included(Sub, Es) :-
same_length(Es, Xs),
Sub = [_|_], % minimum length: 1
append(_, Sub, Xs), % maximum length: as long as `Es`
maplist(list_member(Es), Sub).
Let's run the queries the OP gave!
First up, use-cases we expect to succeed:
?- member(Xs, [[1,4],[2,3],[2,3,5],[3,4]]), all_included(Xs, [1,2,3,4,5]).
Xs = [1,4]
; Xs = [2,3]
; Xs = [2,3,5]
; Xs = [3,4]
; false.
Next up, some use-cases we expect to fail:
?- member(Xs, [[],[2,6],[1,6]]), all_included(Xs, [1,2,3,4,5]).
false.
?- all_included([3,5], [1,2,5]).
false.

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(_,_).

How can I check if an element in the list is an empty list: []?

How can I check if an element in the list is an empty list: [] ?
I've got the following:
display_degrees([A,B,C,D]):- write(B).
display_degrees([A,B,C,D]):- B==[], nl,write('has no degree'), nl, !.
When I enter in something like:
display_degrees([1,[],3,4]).
I just get: [] instead of 'has no degree'. Is my syntax wrong? Can I not add a clause to this predicate like this?
You're getting this behavior because proof search stops when a goal has succeeded. When you type
display_degrees([1,[],3,4]).
the first rule unifies, and it writes B. Since it was a success, it stops. You can ask Prolog to keep searching, and then it will find the second clause. In swipl, I get
?- [foo].
?- display_degrees([1,[],3,4]).
[]
true r % I type 'r' there
has no degree
true.
If you're just learning Prolog, I suggest you avoid the cut operator ! for some time. Also, doing IO is not the most intuitive thing. I would try some exercises with defining things like natural numbers and recursive functions. E.g., plus:
plus(z, X, X).
plus(s(X), Y, s(Z)) :- plus(X, Y, Z).
The problem with what you have is that the more general rule will fire first. You could switch the order:
display_degrees([A,[],C,D]) :- nl, write('has no degree'), nl, !.
display_degrees([A,B,C,D]) :- write(B).
I could just as well have written for the first predicate:
display_degrees([A,B,C,D]) :- B == [], nl, write('has no degree'), nl, !.
But the "shortcut" I show initially is more idiomatic for a Prolog predicate like this.
I kept the cut since you know you deterministically want one choice. The first rule will match if and only if the second list element is [].
| ?- display_degrees([1,[],3,4]).
has no degree
yes
| ?- display_degrees([1,2,3,4]).
2
yes
| ?-