Prolog program comprehension - prolog

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 -----

Related

Better pure version of same_length/2

Given the frequent pure definition of same_length/2 as
same_length([],[]).
same_length([_|As], [_|Bs]) :-
same_length(As, Bs).
?- same_length(L, [_|L]).
loops.
Is there a pure definition that does not loop for such cases? Something in analogy to the pure (but less efficient) version of append/3 called append2u/3.
I know how to catch such cases manually with var/1 and the like, but ideally a version that is just as pure as the original definition would be desirable. Or at least it should be simple.
What I have tried is the definition above.
One clarification seems to be in order:
Note that there are certain queries that inherently must not terminate. Think of:
?- same_length(Ls, Ks).
Ls = [], Ks = []
; Ls = [_A], Ks = [_B]
; Ls = [_A,_B], Ks = [_C,_D]
; Ls = [_A,_B,_C], Ks = [_D,_E,_F]
; Ls = [_A,_B,_C,_D], Ks = [_E,_F,_G,_H]
; ... .
There is no other way to enumerate all solutions using the language of syntactic answer substitutions.
But still an implementation may terminate for the queries given.
This answer aims at minimising runtime costs.
It is built on '$skip_max_list'/4 and runs on Scryer Prolog.
First up, some auxiliary code:
:- use_module(library(lists)).
'$skip_list'(N,Xs0,Xs) :-
'$skip_max_list'(N,_,Xs0,Xs).
is_list([]).
is_list([_|Xs]) :-
is_list(Xs).
sam_length_([],[]).
sam_length_([_|Xs],[_|Ys]) :-
sam_length_(Xs,Ys).
Now the main dish:
sam_length(Ls1,Ls2) :-
'$skip_list'(L1,Ls1,Rs1),
( Rs1 == []
-> length(Ls2,L1)
; var(Rs1),
'$skip_max_list'(L2,L1,Ls2,Rs2),
( L2 < L1
-> var(Rs2),
Rs1 \== Rs2,
'$skip_max_list'(_,L2,Ls1,Ps1),
sam_length_(Ps1,Rs2)
; '$skip_list'(N2,Rs2,Ts2),
( Ts2 == []
-> M1 is N2-L1,
length(Rs1,M1)
; var(Ts2),
( N2 > 0
-> Ts2 \== Rs1,
sam_length_(Rs2,Rs1) % switch argument order
; Rs1 == Rs2
-> is_list(Rs1) % simpler enumeration
; sam_length_(Rs1,Rs2)
)
)
)
).
Sample queries:
?- sam_length(L,[_|L]).
false.
?- sam_length([_],L).
L = [_A].
?- sam_length(L,M).
L = [], M = []
; L = [_A], M = [_B]
; ... .
A solution using '$skip_max_list'/4:
% Clause for `?- L = [a|L], same_length(L, _)`.
same_length(As, Bs) :-
(Cs = As ; Cs = Bs),
'$skip_max_list'(_, _, Cs, Cs0),
subsumes_term([_|_], Cs0), !,
false.
% Clause for `?- same_length(L, [_|L])`.
same_length(As, Bs) :-
As \== Bs,
'$skip_max_list'(S, _, As, As0),
'$skip_max_list'(T, _, Bs, Bs0),
As0 == Bs0,
S \== T, !,
false.
same_length(As, Bs) :-
same_length_(As, Bs).
same_length_([], []).
same_length_([_|As], [_|Bs]) :-
same_length_(As, Bs).
Queries:
?- L = [a|L], same_length(L, _).
false.
?- same_length(L, [_|L]).
false.
?- same_length([_], L).
L = [_A].
?- same_length(L, M).
L = [], M = []
; L = [_A], M = [_B]
; ... .
UPDATED SOLUTION
Here is my solution:
same_length(A, A).
same_length([_|A], [_|B]) :- same_length(A, B).
?- same_length(L, [_|L]).
L = [_1696|L]
I am not sure if it has all the properties you're looking for. For example if you call
? - same_length(L, [1,2,3]).
then it lists many answers, e.g. L = [_X, 2, 3], rather than just [_X, _Y, _Z]. But it's pure and produces a correct answer for the query quoted.

prolog max_min_eval/2 solution issue

I want to create a predicate max_min_eval/2 or max_min_eval(List,Result) which read a list like this [1,min,2,max,4,max,3] -> (((1 min 2) max 4) max 3) in eclipse prolog and put the Result into a varialble. How can I do this?
This is my code:
%% seperate_lists/3
%% seperate_lists(List,Lets,Nums)
seperate_lists([], [], []) .
seperate_lists([X|Xs] , [X|Lets] , Nums) :-
not(number(X)),
!,
seperate_lists(Xs,Lets,Nums).
seperate_lists( [X|Xs] , Lets, [X|Nums] ) :-
number(X),
!,
seperate_lists(Xs,Lets,Nums).
seperate_lists([_|Xs], Lets, Nums) :-
seperate_lists(Xs,Lets,Nums).
%% max_min_eval/2
%% max_min_eval(List,Result)
max_min_eval_aux(_,[Result],Result).
max_min_eval_aux(Lets, Nums, Result) :-
[LH|LT] = Lets,
[NH1,NH2|NT] = Nums,
(
('max' = LH, max(NH1,NH2,Result), append([Result],NT,NewNums), NewLets = LT, max_min_eval_aux(NewLets,NewNums,Result));
('min' = LH, min(NH1,NH2,Result), append([Result],NT,NewNums), NewLets = LT, max_min_eval_aux(NewLets,NewNums,Result))
).
max_min_eval(List,Result) :-
seperate_lists(List,Lets,Nums),
max_min_eval_aux(Lets,Nums,Result).
The problem is that it doesn't work for ?- max_min_eval([1,max,10,min,2],Result), only works for 3 element list like this ?- max_min_eval([1,max,4],Result) or ?- max_min_eval([2,min,5],Result)
You may greedily evaluate the expression:
max_min_eval([First|Tail], Res):-
max_min_eval(Tail, First, Res).
max_min_eval([],Res, Res).
max_min_eval([Op, R|Tail], L, Res):-
max_min_eval_op(Op, L, R, L1),
max_min_eval(Tail, L1, Res).
max_min_eval_op(max, L, R, Res):-
max(L, R, Res).
max_min_eval_op(min, L, R, Res):-
min(L, R, Res).
Add these procedures if your prolog processor does not have max/3 and min/3:
max(A,B,M):- M is max(A,B).
min(A,B,M):- M is min(A,B).
Sample run:
?- max_min_eval([1,min,2,max,4,max,3], R).
R = 4.

Perform list conversion,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.

Splitting a list into 2 lists at a pivot in prolog

I want to split a list into 2 lists at a pivot P, if the number is less than P it goes into L1 and if it is greater than P then it will go into L2.
This is what I have so far, I am able to split a list L into L1 = [[],[]] in this form. But I want to split the list into 2 lists L1, and L2, how would I do that?
split(L,P,L1):-
split(L,P,[],L1).
split([],_,[],[]).
split([],_,X,[X]) :- X \= [].
split([P|T],P,[],L1) :- split(T,P,[],L1).
split([P|T],P,L,[L|L1]) :- L \= [], split(T,P,[],L1).
split([H|T],P,S,L1) :- H \= P, append(S, [H], S2), split(T,P,S2,L1).
You only need three rules to implement this predicate:
:- use_module(library(clpfd)).
split([], _, [], []).
split([H|T], P, L1, [H|T2]) :-
H #>= P,
split(T, P, L1, T2).
split([H|T], P, [H|T1], L2) :-
H #< P,
split(T, P, T1, L2).
The code is fairly straightforward
Note that, because of library(clpfd), this predicate also works e.g. when the initial list and the pivot are not known:
?- split(L,P,[5,47],[101]).
L = [101, 5, 47],
P in 48..101 ;
L = [5, 101, 47],
P in 48..101 ;
L = [5, 47, 101],
P in 48..101 ;
false.
Using partition/4
As mentionned in a comment, you can use partition/4 to do this:
split(L, P, L1, L2) :-
partition(zcompare(>,P), L, L1, L2).
However, this will not exhibit as many different behaviours as the first implementation.

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.

Resources