Perform list conversion,Prolog - prolog

[a,a,a,a,b,c,c,a,a,d,e,e,e,e] => [[4,a],b,[2,c],[2,a],d,[4,e]].
please help me solve this problem
I have this code, but I do not know how to bring it to the one that is required or how can it be done differently or easier:
p([]):- !.
p( [X] ):- !, write(X).
p( [X | T] ):-!, write(X), write(", "), p(T).
first_letter([H], Let, Num, Mid, Res):-
( H = Let, New_num is Num +1,
G = [Let], Prom = [New_num | G],
Res = [Prom | Mid], !
; true
),
( H \= Let,New_num is 1,
G = [Let], Prom = [Num | G], New_mid = [Prom | Mid],
SG = [H], Sec_Prom = [New_num | SG],
Res = [Sec_Prom | New_mid],
!
; true
).
first_letter([H | T], Let, Num, Mid, Res):-
( H = Let,New_Num is (Num + 1),
first_letter(T, Let, New_Num, Mid, Res),
!
; true
),
( H \= Let, G = [Let], Prom = [Num | G],
New_mid = [Prom | Mid],
first_letter(T, H, 1, New_mid, Res),
!
; true
).
nreverse([T], Res):- Res = [T], !.
nreverse([H | T], Res):-
nreverse(T, Resal),
append(Resal, [H], Res). %nehvost
start:-
T = [a,a,a,a,b,c,c,a,a,d,e,e,e,e], T = [H | _],
first_letter(T, H, 0, [], Res),
nreverse(Res, End),
p(End).

squeeze([], []).
squeeze([X|Xs], Ys) :-
squeeze(Xs, X-1, [], Ys).
squeeze([], Current, Acc, Ys) :- reverse(Ys, [Current|Acc]).
squeeze([X|Xs], X-N, Acc, Ys) :-
N1 is N+1,
squeeze(Xs, X-N1, Acc, Ys).
squeeze([X|Xs], C-N, Acc, Ys) :-
dif(X,C),
squeeze(Xs, X-1, [C-N|Acc], Ys).
gives
?- squeeze([a,a,a,a,b,c,c,a,a,d,e,e,e,e], X).
X = [a-4, b-1, c-2, a-2, d-1, e-4]
I have used pairs from swi-prolog to represent and element and its length. You can change it to list if you want, just replace any instance of A-B with [A, B] in the above code.

It's an exercice to learn fold/4
:- use_module(library(lambda)).
start(Out) :-
T = [a,a,a,a,b,c,c,a,a,d,e,e,e,e],
foldl(\X^Y^Z^(nth0(_, Y , [A,X], R)
-> A1 is A + 1,
Z = [[A1, X] | R]
; Z = [[1, X] | Y]),
T, [], Out_),
sort(Out_, Out).
Result :
?- start(Out).
Out = [[1, b], [1, d], [2, c], [4, e], [6, a]].

Ok, to reduce confusion: I saw your other question first where you more or less ask about to turn the answer from rajashekar to your desired format. I agree with rajashekar, so I won't do all the work for you but it still tickles to simplify the code, so here a step closer to your goal:
At first I would remove the fourth argument. It is possible to do it with just 3 arguments and you don't even have to reverse your Acc.
Second, you want to have a list-writing ([a, 4]) instead of a minus-pair-writing (a-4).
Third you want to have a special case where single elements are displayed without the list notation (b instead of [b, 1]).
This is the code when you apply the changes 1 and 3; part 2 you can just do by reading the answer by rajashekar:
squeeze1([], []).
squeeze1([X|Xs], Ys) :-
squeeze1(Xs, X-1, Ys).
squeeze1([], Current, [Current]).
squeeze1([X|Xs], X-N, Acc) :-
N1 is N+1,
squeeze1(Xs, X-N1, Acc).
squeeze1([X|Xs], C-N, [C-N|Acc]) :-
N>1,
dif(X,C),
squeeze1(Xs, X-1, Acc).
squeeze1([X|Xs], C-1, [C|Acc]) :-
dif(X,C),
squeeze1(Xs, X-1, Acc).
?- squeeze1([a,a,a,a,b,c,c,a,a,d,e,e,e,e], X).
X = [a-4, b, c-2, a-2, d, e-4] ;
false.

Related

Prolog program comprehension

This is the program I have:
foo(L,[H|R1]) :-
foo(L,R1,H).
foo([H],[],H).
foo([H|T],[H|T1],R) :-
foo(T,T1,R).
This is the query:
foo([1,2,3,4,5,6],X).
I don't understand what this program does, can someone help me and explain how does it work?
You could try to refactor it. If I start with:
foo(L, [H|R1]) :-
foo(L, R1, H).
foo([H], [], H).
foo([H|T], [H|T1], R) :-
foo(T, T1, R).
I can change the argument order foo(1,2,3) to foo(2,3,1):
foo(L,[H|R1]) :-
foo(R1, H, L).
foo([], H, [H]).
foo([H|T1], R, [H|T]) :-
foo(T1, R, T).
Now I can change the 2-nd argument of foo, and pass [H] instead of H:
foo(L, [H|R1]) :-
foo(R1, [H], L).
foo([], H, H).
foo([H|T1], R, [H|T]) :-
foo(T1, R, T).
Now you can rename the predicates to roll and append:
roll(L, [H|R1]) :-
append(R1, [H], L).
append([], H, H).
append([H|T1], R, [H|T]) :-
append(T1, R, T).
In Prolog, there is no need to understand the source code. Instead, let Prolog do this for you. Just ask the most general query:
?- foo(L,R).
L = [_A],
R = [_A]
; L = [_A,_B],
R = [_B,_A]
; L = [_A,_B,_C],
R = [_C,_A,_B]
; L = [_A,_B,_C,_D],
R = [_D,_A,_B,_C]
; L = [_A,_B,_C,_D,_E],
R = [_E,_A,_B,_C,_D]
; L = [_A,_B,_C,_D,_E,_F],
R = [_F,_A,_B,_C,_D,_E]
; L = [_A,_B,_C,_D,_E,_F,_G],
R = [_G,_A,_B,_C,_D,_E,_F]
; L = [_A,_B,_C,_D,_E,_F,_G,_H],
R = [_H,_A,_B,_C,_D,_E,_F,_G]
; ... .
Do you see a pattern here?
To understand it easier, put the recursive clause above the base one:
foo( [H | T], [H | T1], R) :- foo( /* T = [_|_] */
T, T1, R).
foo( [R], [], R).
So we advance along the two lists (that hold the same elements, H) until we hit the last element in the first list ([R]), at which point the second list is exhausted ([]), and we get hold of that last element (R).
This means that foo( A, B, R) :- append( B, [R], A).. Thus,
foo( L, [E | R1]) :- % foo( L, R1, E).
append( R1, [E], L). % R1 ++ [E] = L
i.e. foo( L, M) relates two lists L, M, where L is M with its first element E "flipped" to the list's end:
L : .............E
M : E.............
% ---- R1 -----

Write a set of prolog rules that returns a list which contains the larger item in each position in two lists of the same length?

Very, VERY new to Prolog here. My function needs to compare two lists of equal length by taking the larger number into a new list (e.g. larger([3, 12, 5], [6, 3, 11], X) returns X = [6, 12, 11].) This is what I have, but it is not getting me what I need:
larger([],[],[]).
larger([H|T],[E|A],X):- H > E, larger([T],[A],[H|X]).
larger([H|T],[E|A],X):- H < E, larger([T],[A],[E|X]).
Any help is much appreciated.
The other answer is OK, this is a slightly different approach.
Two clauses should be enough:
larger([], [], []).
larger([X|Xs], [Y|Ys], [Z|Zs]) :-
/* Z is the larger number from (X, Y) */
larger(Xs, Ys, Zs).
How you do the part in the comments depends on your exact problem statement and maybe the implementation. At least SWI-Prolog and GNU-Prolog both have an arithmetic function max() that you can use like this in the above:
larger([], [], []).
larger([X|Xs], [Y|Ys], [Z|Zs]) :-
Z is max(X, Y),
larger(Xs, Ys, Zs).
This is arguably nicer than the solution with three clauses because it won't leave behind unnecessary choice points. Like the other solution, it will work fine as long as the two lists have numbers in them.
This would be identical to using a maplist, for example like this:
larger(Xs, Ys, Zs) :-
maplist(max_number, Xs, Ys, Zs).
max_number(X, Y, Z) :- Z is max(X, Y).
You're not far.
Try with
larger([], [], []).
larger([H | T], [E | A], [H | X]) :-
H > E,
larger(T, A, X).
larger([H | T], [E | A], [E | X]) :-
H =< E,
larger(T, A, X).
If I'm not wrong, there are three errors in your code.
(1) you have to translate the bigger head value (H or E) in the third argument of larger/3, not in the recursive call
% ------- H added here ---v
larger([H | T], [E | A], [H | X]) :-
H > E,
larger(T, A, X).
% not here ----^
(2) T and A, the tails in [H|T] and [E|A], are lists, so you have to pass they recursively as T and A, not as [T] and [A]
larger([H | T], [E | A], [H | X]) :-
H > E,
larger(T, A, X).
% not larger([T], [A], X)
(3) if you have the cases H > E and H < E, your code fail when H is equal to E; one solution is H > E and H =< E; the secon case cover H equal to E.

Prolog append/3 realization with more determinism?

It is folk knowledge that append(X,[Y],Z) finds the last element
Y of the list Z and the remaining list X.
But there is some advantage of having a customized predicate last/3,
namely it can react without leaving a choice point:
?- last([1,2,3],X,Y).
X = 3,
Y = [1,2]
?- append(Y,[X],[1,2,3]).
Y = [1,2],
X = 3 ;
No
Is there a way to realize a different implementation of
append/3 which would also not leave a choice point in the
above example?
P.S.: I am comparing:
/**
* append(L1, L2, L3):
* The predicate succeeds whenever L3 unifies with the concatenation of L1 and L2.
*/
% append(+List, +List, -List)
:- public append/3.
append([], X, X).
append([X|Y], Z, [X|T]) :- append(Y, Z, T).
And (à la Gertjan van Noord):
/**
* last(L, E, R):
* The predicate succeeds with E being the last element of the list L
* and R being the remainder of the list.
*/
% last(+List, -Elem, -List)
:- public last/3.
last([X|Y], Z, T) :- last2(Y, X, Z, T).
% last2(+List, +Elem, -Elem, -List)
:- private last2/4.
last2([], X, X, []).
last2([X|Y], U, Z, [U|T]) :- last2(Y, X, Z, T).
One way to do it is to use foldl/4 with the appropriate help predicate:
swap(A, B, B, A).
list_front_last([X|Xs], F, L) :-
is_list(Xs),
foldl(swap, Xs, F, X, L).
This should be it:
?- list_front_last([a,b,c,d], F, L).
F = [a, b, c],
L = d.
?- list_front_last([], F, L).
false.
?- list_front_last([c], F, L).
F = [],
L = c.
?- Ys = [y|Ys], list_front_last(Ys, F, L).
false.
Try to see if you can leave out the is_list/1 from the definition.
As I posted:
append2(Start, End, Both) :-
% Preventing unwanted choicepoint with append(X, [1], [1]).
is_list(Both),
is_list(End),
!,
append(Start, End, Both),
!.
append2(Start, End, Both) :-
append(Start, End, Both),
% Preventing unwanted choicepoint with append(X, Y, [1]).
(End == [] -> ! ; true).
Result in swi-prolog:
?- append2(Y, [X], [1,2,3]).
Y = [1, 2],
X = 3.

Replace elements of a list in Prolog

I have a predicate variablize/3 that takes a list and replaces each item, in turn, with a variable, example:
% ?- variablize([a,b,c], X, L).
% L = [[X, b, c], [a, X, c], [a, b, X]]
Now I am trying to extend this predicate to accept a list of variables, example:
% ?- variablize([a,b,c], [X,Y], L).
% L = [[X, Y, c], [X, b, Y], [a, X, Y]]
My code so far is:
replace_at([_|Tail], X, 1, [X|Tail]).
replace_at([Head|Tail], X, N, [Head|R]) :- M is N - 1, replace_at(Tail, X, M, R).
replace_each([], _, _, [], _).
replace_each([_|Next], Orig, X, [Res|L], N) :-
replace_at(Orig, X, N, Res),
M is N + 1,
replace_each(Next, Orig, X, L, M).
variablize(I, X, L) :- replace_each(I, I, X, L, 1).
Any pointers? Do I extend replace_at/4 to have a list of indexes that should be skipped?
A simplified, builtin based way of implementing variablize/3
variablize(I, X, L) :-
bagof(R, U^select(U, I, X, R), L).
put in evidence that instead of select/4 we could have a distribute/3 that applies replacements of elements of X, when X becomes a list. select/4 can be implemented in this way
myselect(B, I, X, R) :-
append(A, [B|C], I), append(A, [X|C], R).
and this form is convenient because we have the part to the right of input list I, where I suppose you need to distribute remaining variables. Then a recursion on X elements should do:
distribute(I, [X|Xs], L) :-
append(A, [_|C], I),
distribute(C, Xs, R),
append(A, [X|R], L).
distribute(I, [], I).
distribute/3 behaves this way:
?- distribute([a,b,c,d],[1,2],X).
X = [1, 2, c, d] ;
X = [1, b, 2, d] ;
X = [1, b, c, 2] ;
X = [a, 1, 2, d] ;
X = [a, 1, c, 2] ;
X = [a, b, 1, 2] ;
false.
thus
variablize_l(I, X, L) :-
bagof(R, distribute(I, X, R), L).
give us:
?- variablize_l([a,b,c],[X,Y],L).
L = [[X, Y, c], [X, b, Y], [a, X, Y]].
edit
I initially wrote this way, for here the evidence of separating the distribution phase from list construction:
replace_v([_|T], X, [X|T]).
replace_v([L|T], X, [L|R]) :-
replace_v(T, X, R).
variablize(I, X, L) :-
bagof(E, replace_v(I, X, E), L).
variablize(L1,L2,L) :-
append(L1,L2,L3),
length(L1,Len1),
length(L2,Len2),
findall(L4,(combination(L3,Len1,L4),var_count(L4,Len2)),L).
combination(X,1,[A]) :-
member(A,X).
combination([A|Y],N,[A|X]) :-
N > 1,
M is N - 1,
combination(Y,M,X).
combination([_|Y],N,A) :-
N > 1,
combination(Y,N,A).
var_count([],0).
var_count([V|R],N) :-
var(V),
var_count(R,N1),
N is N1 + 1,
!.
var_count([A|R],N) :-
var_count(R,N).

creating lists, searching sth which has been given and making combination on prolog

I want to make a Prolog program.
Predicate will be like this:
name(name, failedCourse, age)
Database of the program is:
name(george, math, 20).
name(steve, phys, 21).
name(jane, chem, 22).
I want to implement the predicate nameList(A, B). A means list of names, B means number of names on the list. For example:
nameList([george, steve],2). returns true
nameList([george, steve],X). returns X=2
nameList(X,2). returns X=[george, steve]; X=[george, jane]; X=[steve, jane]
nameList([martin],1). returns false (because martin is not included database.)
I wanted to make a list that includes all names on the database. For that reason I made a findall.
descend(X,Y,A) :- name(X,Y,A).
descend(X,Y,A) :- name(X,Z,A),descend(Z,Y,A).
findall(director(X),descend(Y,X),Z).
?- findall(B,descend(B,X,Y),A). returns A = [george, steve, jane].
But I could not figure it out to use list A in predicates :( I cannot search the list for A in the nameList.
If you help me, I will be very grateful.
The main thing you need is a predicate that calculates combinations of a given length and of a given list:
comb(0, _, []).
comb(N, [X | T], [X | Comb]) :-
N > 0,
N1 is N - 1,
comb(N1, T, Comb).
comb(N, [_ | T], Comb) :-
N > 0,
comb(N, T, Comb).
Usage:
?- comb(2, [a, b, a], Comb).
Comb = [a, b] ;
Comb = [a, a] ;
Comb = [b, a] ;
false.
(See more here.)
Now you can just apply this predicate on your data:
name(george, math, 20).
name(steve, phys, 21).
name(jane, chem, 22).
name_list(L, N) :-
findall(X, name(X, _, _), Xs),
length(Xs, Len),
between(0, Len, N),
comb(N, Xs, L).
Usage examples:
?- name_list(L, N).
L = [],
N = 0 ;
L = [george],
N = 1 ;
L = [steve],
N = 1 ;
L = [jane],
N = 1 ;
L = [george, steve],
N = 2 ;
L = [george, jane],
N = 2 ;
L = [steve, jane],
N = 2 ;
L = [george, steve, jane],
N = 3 ;
false.
?- name_list([george, steve], N).
N = 2 ;
false.
?- name_list(L, 2).
L = [george, steve] ;
L = [george, jane] ;
L = [steve, jane] ;
false.
name(george, math, 20).
name(steve, phys, 21).
name(jane, chem, 22).
name_list(Name_List,N) :-
integer(N),
findall(Name,name(Name,_,_),L),
combination(L,N,Name_List).
name_list(Name_List,N) :-
var(N),
findall(Name,name(Name,_,_),L),
length(L,Len),
for(1,N,Len),
combination(L,N,Name_List).
combination(X,1,[A]) :-
member(A,X).
combination([A|Y],N,[A|X]) :-
N > 1,
M is N - 1,
combination(Y,M,X).
combination([_|Y],N,A) :-
N > 1,
combination(Y,N,A).

Resources