Why the end of result list is not []? - prolog

I tried to output a list only contain the unique element. But the result is not perfect.
list_concatenation([],L,L).
list_concatenation([X1|L1],L2,[X1|L3]) :-
list_concatenation(L1,L2,L3).
list_member(X, [X|_]).
list_member(X, [_|TAIL]) :- list_member(X,TAIL),!.
toset([],_).
toset([X|TAIL],SET):-
list_member(X,SET),
toset(TAIL,SET).
toset([X|TAIL],SET):-
\+ list_member(X,SET),
list_concatenation([X],SET,NEWSET),
toset(TAIL,NEWSET).
For example:
?- toset([1,1,2,3],X).
the result should be 'X = [1, 2, 3]' but now, it is 'X = [1, 2, 3|_16998]'

You actually implement the toset/2 the wrong way. You actually use list_member/2 here to add an element to the list. Indeed, if you use a free variable, you get:
?- list_member(2, L).
L = [2|_3616] ;
L = [_3614, 2|_3622].
The list_member/2 itself, is not correctly implemented as well. The cut (!) here prevents to keep yielding values. You thus should remove the cut:
list_member(X, [X|_]).
list_member(X, [_|Tail]) :-
list_member(X,Tail).
This thus can yield all possible lists where 2 is a member:
?- list_member(2, L).
L = [2|_3412] ;
L = [_3410, 2|_3418] ;
L = [_3410, _3416, 2|_3424] ;
L = [_3410, _3416, _3422, 2|_3430] ;
...
But now the problem still remains: you should not use list_member/2 here to add elements to the list, you can use an accumulator here that keeps track of the elements already yielded, and then eventually return that accumulator, like:
toset(L, S) :-
toset(L, [], S).
toset([], A, S):-
reverse(A, S).
toset([H|T], A, L) :-
( member_list(H, A)
-> toset(T, [H|A], L)
; toset(T, A, L)
).
We thus keep prepending the values to the accumulator, and in the end, we reverse/2 [swi-doc] the accumulator, and return that as a result.

Related

Prolog every ith element in sublist

Is it possible to copy every ith element from a list to a sublist with just one ternary predicate sublist(Element, List1, List2) and built-in length and append?
I know, with 4-element auxiliary predicates, it becomes rather trivial, but it isn't what I need.
Can anybody suggest a strategy?
with some builtins a declarative solution is really easy:
sublist(Element, List1, List2) :-
findall(E, (nth1(I, List1, E), 0 is I mod Element), List2).
while explicitly iterating:
sublist(Element, List1, List2) :-
( N is Element-1,
length(T, N),
append(T, [E|R], List1)
-> sublist(Element, R, ListR),
List2 = [E|ListR]
; List2 = []
).
where you can see the how to use Boris' suggestion
You can use lentgth/2 with the first argument a variable and the second an integer, to create a list of not instantiated variables, like this:
?- length(L, 4).
L = [_G936, _G939, _G942, _G945].
If you now use append/3 with this list as the first argument, and a variable as the second, it will split the list in your third argument:
?- length(A, 4), append(A, B, [a,b,c,d,e,f,g,h]).
A = [a, b, c, d],
B = [e, f, g, h].
So if you want say the 5th element of a list, you could take the head of the second argument:
?- length(A, 4), append(A, [Fifth|Rest], [a,b,c,d,e,f,g,h]).
A = [a, b, c, d],
Fifth = e,
Rest = [f, g, h].
This is not a solution but a valid strategy:
every_ith(I, In, [X|Ys]) :-
N is I - 1,
length(Prefix, N),
append(Prefix, [X|Xs], In),
every_ith(I, Xs, Ys).

Prolog separating lists

Hello is there any way to separate a list in Prolog into two other lists, the first includes everything before an element and the second everything after the element. For example
A=[1,2,3,5,7,9,0] and element=5
the two lists should be
A1=[1,2,3] and A2=[7,9,0]
I don't care about finding the element just what to do next
it's easy as
?- Elem = 5, A = [1,2,3,5,7,9,0], append(A1, [Elem|A2], A).
edit to explain a bit...
append/3 it's a relation among 3 lists.
It's general enough to solve any concatenation on proper lists - when not there are circular arguments.
The comparison it's a plain unification, that take place on second argument. That must be a list beginning with Elem. Prolog list constructor syntax is [Head|Tail]. To make unification succeed, Elem must match the Head.
Here's an alternative method, illustrating how to handle it with list recursion:
split([E|T], E, [], T).
split([X|T], E, [X|LL], LR) :-
X \== E,
split(T, E, LL, LR).
Or better, if your Prolog supports dif/2:
split([E|T], E, [], T).
split([X|T], E, [X|LL], LR) :-
dif(X, E),
split(T, E, LL, LR).
Examples:
| ?- split([1,2,3,4,5], 3, L, R).
L = [1,2]
R = [4,5] ? ;
no
| ?- split([1,2,3,4,5], 5, L, R).
L = [1,2,3,4]
R = [] ? ;
(1 ms) no
| ?- split([1,2,3,4,5], 1, L, R).
L = []
R = [2,3,4,5] ? ;
no
| ?-
It is a sort of specialized twist on append/3 as CapelliC showed.

Getting the product of a list from left to right

How do you get the product of a list from left to right?
For example:
?- product([1,2,3,4], P).
P = [1, 2, 6, 24] .
I think one way is to overload the functor and use 3 arguments:
product([H|T], Lst) :- product(T, H, Lst).
I'm not sure where to go from here.
You can use library(lambda) found here : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl
Quite unreadable :
:- use_module(library(lambda)).
:- use_module(library(clpfd)).
product(L, R) :-
foldl(\X^Y^Z^(Y = []
-> Z = [X, [X]]
; Y = [M, Lst],
T #= X * M,
append(Lst, [T], Lst1),
Z = [T, Lst1]),
L, [], [_, R]).
Thanks to #Mike_Hartl for his advice, the code is much simple :
product([], []).
product([H | T], R) :-
scanl(\X^Y^Z^( Z #= X * Y), T, H, R).
seems like a list copy, just multiplying by last element handled. Let's start from 1 for the leftmost element:
product(L, P) :-
product(L, 1, P).
product([X|Xs], A, [Y|Ys]) :-
Y is X * A,
product(Xs, Y, Ys).
product([], _, []).
if we use library(clpfd):
:- [library(clpfd)].
product([X|Xs], A, [Y|Ys]) :-
Y #= X * A,
product(Xs, Y, Ys).
product([], _, []).
it works (only for integers) 'backward'
?- product(L, [1,2,6,24]).
L = [1, 2, 3, 4].
Probably very dirty solution (I am new to Prolog):
product([ListHead|ListTail], Answer) :-
product_acc(ListTail, [ListHead], Answer).
product_acc([ListHead|ListTail], [AccHead|AccTail], Answer) :-
Product is ListHead * AccHead,
append([Product, AccHead], AccTail, TempList),
product_acc(ListTail, TempList, Answer).
product_acc([], ReversedList, Answer) :-
reverse(ReversedList, Answer).
So basically at the beginning we call another predicate which has
extra "variable" Acc which is accumulator list.
So we take out head (first number) from original list and put it in
to Accumulator list.
Then we always take head (first number) from original list and
multiply it with head (first number) from accumulator list.
Then we have to append our new number which we got by multiplying
with the head from accumulator and later with the tail
Then we call same predicate again until original list becomes empty
and at the end obviously we need to reverse it.
And it seems to work
?- product([1,2,3,4], L).
L = [1, 2, 6, 24].
?- product([5], L).
L = [5].
?- product([5,4,3], L).
L = [5, 20, 60].
Sorry if my explanation is not very clear. Feel free to comment.

remove element from list without removing all duplicates

i want remove elements from a list but if i do this:
deletelist([3,1,2,3,4], [3], [3,1,2,4])
how remove only a 3 and not get this answer:
deletelist([3,1,2,3,4], [3], [1,2,4])
Thanks!
select/3 it's an useful builtin, frequently used to generate and test, and you can use to delete an element:
?- select(3,[3,1,2,3,4],L).
L = [1, 2, 3, 4] ;
L = [3, 1, 2, 4] ;
false.
each call removes a match, then you can control the desired behaviour
edit
to delete all elements from the second list:
deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
select(D, With, WithoutD),
deletelist(WithoutD, Ds, Without).
Note that this will fail if any of elements to be deleted will not be found in list. To avoid this, apply a 'if .. then .. else ..'
deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
( select(D, With, WithoutD)
-> deletelist(WithoutD, Ds, Without)
; deletelist(With, Ds, Without)
).
Now deletelist/3 will not enumerate all possible deletions. It commits to the first found. To resume the initial behaviour, that give on bactracking all different deletions, a less efficient procedure is required:
deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
select(D, With, WithoutD),
deletelist(WithoutD, Ds, Without).
deletelist(With, [D|Ds], Without) :-
\+ select(D, With, _),
deletelist(With, Ds, Without).
If you want to get just unique values in list - use function list_to_set/2:
list_to_set([3,1,2,3,4],X) gives X = [3, 1, 2, 4].
EDIT:
So gnu prolog doesn't have built-in predicate list_to_set. You have to write it yourself.
For this you must define set concept. What is set of list ? Set should have these attributes:
Set size must be less or equal to List size.
All members of Set must be members of List.
All members of List must be members of Set.
Set must not contain duplicated values.
Based on these assumptions you can write set_from_list predicate like this:
elem_unique(Elem, List) :-
delete(List, Elem, ListWithoutElem),
length(List, OrgLength),
length(ListWithoutElem, DelLength),
DelLength + 1 =:= OrgLength.
nth_elem_isUnique(N, List) :-
nth1(N, List, Elem),
elem_unique(Elem, List).
nth_elemOfList1_isMemberOfList2(N, List1, List2) :-
nth1(N, List1, Elem),
member(Elem, List2).
elements_from_nth_areUnique(N, List) :-
(length(List, Len),
N > Len) %stoping condition for recursion
;
(nth_elem_isUnique(N, List),
M is N + 1,
elements_from_nth_areUnique(M, List) %recursion part
).
listIsUnique(List) :-
elements_from_nth_areUnique(1, List).
elements_from_nth_inList1_areMembersOfList2(N, List1, List2) :-
(length(List1, Len),
N > Len) %stoping condition for recursion
;
(nth_elemOfList1_isMemberOfList2(N, List1, List2),
M is N + 1,
elements_from_nth_inList1_areMembersOfList2(M, List1, List2) %recursion part
).
list2containsList1(List1, List2) :-
elements_from_nth_inList1_areMembersOfList2(1, List1, List2).
set_from_list(Set, List) :-
length(Set, LenSet),
length(List, LenList),
LenSet =< LenList,
list2containsList1(List, Set),
list2containsList1(Set, List),
listIsUnique(Set),
!.
So after calling set_from_list(Set, [3,1,2,3,4]) you will get Set = [3,1,2,4].

Prolog programs - how to make it work?

I have these two programs and they're not working as they should. The first without_doubles_2(Xs, Ys)is supposed to show that it is true if Ys is the list of the elements appearing in Xs without duplication. The elements in Ys are in the reversed order of Xs with the first duplicate values being kept. Such as, without_doubles_2([1,2,3,4,5,6,4,4],X) prints X=[6,5,4,3,2,1] yet, it prints false.
without_doubles_2([],[]).
without_doubles_2([H|T],[H|Y]):- member(H,T),!,
delete(H,T,T1),
without_doubles_2(T1,Y).
without_doubles_2([H|T],[H|Y]):- without_doubles_2(T,Y).
reverse([],[]).
reverse([H|T],Y):- reverse(T,T1), addtoend(H,T1,Y).
addtoend(H,[],[H]).
addtoend(X,[H|T],[H|T1]):-addtoend(X,T,T1).
without_doubles_21(X,Z):- without_doubles_2(X,Y),
reverse(Y,Z).
The second one is how do I make this program use a string? It's supposed to delete the vowels from a string and print only the consonants.
deleteV([H|T],R):-member(H,[a,e,i,o,u]),deleteV(T,R),!.
deleteV([H|T],[H|R]):-deleteV(T,R),!.
deleteV([],[]).
Your call to delete always fails because you have the order of arguments wrong:
delete(+List1, #Elem, -List2)
So instead of
delete(H, T, T1)
You want
delete(T, H, T1)
Finding an error like this is simple using the trace functionality of the swi-prolog interpreter - just enter trace. to begin trace mode, enter the predicate, and see what the interpreter is doing. In this case you would have seen that the fail comes from the delete statement. The documentation related to tracing can be found here.
Also note that you can rewrite the predicate omitting the member check and thus the third clause, because delete([1,2,3],9001,[1,2,3]) evaluates to true - if the element is not in the list the result is the same as the input. So your predicate could look like this (name shortened due to lazyness):
nodubs([], []).
nodubs([H|T], [H|Y]) :- delete(T, H, T1), nodubs(T1, Y).
For your second question, you can turn a string into a list of characters (represented as ascii codes) using the string_to_list predicate.
As for the predicate deleting vovels from the string, I would implement it like this (there's probably better solutions for this problem or some built-ins you could use but my prolog is somewhat rusty):
%deleteall(+L, +Elems, -R)
%a helper predicate for deleting all items in Elems from L
deleteall(L, [], L).
deleteall(L, [H|T], R) :- delete(L, H, L1), deleteall(L1, T, R).
deleteV(S, R) :-
string_to_list(S, L), %create list L from input string
string_to_list("aeiou", A), %create a list of all vovels
deleteall(L, A, RL), %use deleteall to delete all vovels from L
string_to_list(R, RL). %turn the result back into a string
deleteV/2 could make use of library(lists):
?- subtract("carlo","aeiou",L), format('~s',[L]).
crl
L = [99, 114, 108].
while to remove duplicates we could take advantage from sort/2 and select/3:
nodup(L, N) :-
sort(L, S),
nodup(L, S, N).
nodup([], _S, []).
nodup([X|Xs], S, N) :-
( select(X, S, R) -> N = [X|Ys] ; N = Ys, R = S ),
nodup(Xs, R, Ys).
test:
?- nodup([1,2,3,4,4,4,5,2,7],L).
L = [1, 2, 3, 4, 5, 7].
edit much better, from ssBarBee
?- setof(X,member(X,[1,2,2,5,3,2]),L).
L = [1, 2, 3, 5].

Resources