Implement "For loop" on prolog - algorithm

How to Implement using recursion and cut-off cycle of the counter
(like for i: = 1 downto N do <operator>) ?

my naive implementation, to be seen as an extendend between/3
:- module(loop, [upto/4, downto/4]).
upto(Low,High,_Step,Low) :- Low =< High.
upto(Low,High,Step,Var) :-
Inc is Low+Step,
Inc =< High,
upto(Inc, High, Step, Var).
downto(Low,High,_Step,High) :- Low =< High.
downto(Low,High,Step,Var) :-
Dec is High-Step,
Dec >= Low,
downto(Low, Dec, Step, Var).
usage:
8 ?- forall(upto(0,6,3,V),writeln(V)).
0
3
6
true.
9 ?- forall(downto(0,6,3,V),writeln(V)).
6
3
0
true.
another example, the easiest question posed # this year Prolog programming contest:
icecream(N) :-
loop(N, top(N)),
left, loop(N+1, center), nl,
loop(N+1, bottom(N)).
:- meta_predicate loop(+, 1).
loop(XH, PR) :-
H is XH,
forall(between(1, H, I), call(PR, I)).
top(N, I) :-
left, spc(N-I+1), pop,
( I > 1
-> pop,
spc(2*(I-2)),
pcl
; true
),
pcl, nl.
bottom(N, I) :-
left, spc(I-1), put(\), spc(2*(N-I+1)), put(/), nl.
center(_) :- put(/), put(\).
left :- spc(4).
pop :- put(0'().
pcl :- put(0')).
spc(Ex) :- V is Ex, forall(between(1, V, _), put(0' )).
yields
?- icecream(4).
()
(())
(( ))
(( ))
/\/\/\/\/\
\ /
\ /
\ /
\ /
\/
true.
note: loop in the second snippet is unrelated to first...

The short answer is that you don't.
Prolog is a declaritive language, not a procedural language. It comes from the predicate calculus. You describe the problem space in terms of facts and rules (the "database"). This forms a collection of connected, directed graphs.
You formulate an initial goal that describes the solution to your "problem" and let the inference engine find the solution(s), if any.
The inference engine starts with the initial goal you give it. It evaluates it in terms of the database, walking the graph as it goes, backtracking on failure, until it finds a solution (or not). Backtracking into the initial goal will cause it to look for the next solution, if any.
So the notion of a procedural construct such as a loop is rather non-idiomatic (to say the least) and (in my experience, at least) is pretty much a guarantee of poor performance.

Nicholas Carey is correct in advising you to think declaratively rather than procedurally for Prolog. However I take the question to mean something like, "How can I use Prolog to solve a certain kind of task for which I would employ loops in other languages: in particular, how can I get some set of results or outcomes?" For there are certainly times when, working completely within a declarative idiom, we want to describe N of something. The main difference will be that in instead of having to fit every problem into a loop, there are different ways of solving these kinds of problems depending on the nature of the problem itself.
twinterer's answer works, but is confined to an imperative idiom within a particular language.
Here are possible solutions for three common cases written in common, declarative Prolog idioms:
For numbers from N to M, you can use the built in predicate between(N,M,Num):
?- between(1, 5, X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5.
For a list containing N instances of X, we can use a predicate like this:
n_xs(N, X, Xs) :-
length(Xs, N), % Creates a list of N uninstantiated variables.
maplist('='(X), Xs). % Unifies each variable with X
Then, to get your list:
?- n_xs(5, dingo, Ds).
Ds = [dingo, dingo, dingo, dingo, dingo].
This predicate can also be used to verify the length of a list which already contains a single homogeneous element,
?- n_xs(5, dingo, [dingo, dingo, dingo, dingo, dingo]).
true.
?- n_xs(N, dingo, [dingo, dingo, dingo, dingo, dingo]).
N = 5.
For performing some action N times, we can use something like this:
x_written_n_times(X, N) :-
foreach(between(1,N,_), write(X)).
?- x_written_n_times('dingo\n', 5).
dingo
dingo
dingo
dingo
dingo
true.
More information on kinds of looping behavior can be found at the bottom of this tutorial: http://www.pathwayslms.com/swipltuts/student/index.html

The ECLiPSe language (which basically is a variant of Prolog) has a do/2 predicate which is used to build loops. Using loops in Prolog code is sometimes useful, since it leads to more readable code that is also easier to change.
However, the do/2 predicate is in effect just a macro that gets translated into a recursive predicate, so that underneath it's still recursive:
?- ( for(I,From,To,Inc) do Body ).
maps into something like
?- do__1(From, To, Inc).
do__1(I, To, Inc) :- Inc >= 0, I > To, !.
do__1(I, To, Inc) :- Inc < 0, I < To, !.
do__1(I, To, Inc) :- Body, Next is I+Inc, do__1(Next, To, Inc).
(see the paper Logical Loops, which also gives a number of reasons why logical loops are preferable to pure recursion)

I have written an interpreter for imperative functions in Prolog. This is an example of its usage:
:- initialization(main).
main :-
imperative(Result,[
a = 1,
b = 2,
z = b + 1,
while(a < 10,[
a = a + 1,
(a mod 3 = 0) ->
[writeln(a mod 2),
writeln(a)]
])
]),
writeln(Result).
and this is its implementation:
while(List,Result,Condition,Statements) :-
get_var(List,Condition_,Condition),
(Condition_ -> (imperative(List,Result_,Statements),while(Result_,Result,Condition,Statements));
List=Result).
imperative_(List,Result,Command) :-
(member(A:_,List),
replaceP(A:A1,A:A2,List,Result);Result=[A:A2|List]),
(Command = increment(A,B), A2 is A1 + B;
Command = increment(A), A2 is A1 + 1;
Command = decrement(A), A2 is A1 - 1;
Command = (A = B), get_var(List,A2,B)).
imperative_(List,Result,while(Condition,Statements)) :-
while(List,Result,Condition,Statements).
imperative_(List,List,writeln(A)) :-
get_var(List,A_,A),
writeln(A_).
imperative_(List,Result,(Condition -> Statements)) :-
get_var(List,Condition_,Condition),
(Condition_ -> imperative(List,Result,Statements);List=Result).
imperative(Result,Steps) :- imperative([],Result,Steps).
imperative(List,Result,[Step]) :-
imperative_(List,Result,Step).
imperative(List,Result,[Step|Rest]) :-
imperative_(List,List1,Step), imperative(List1,Result,Rest).
get_var(List,A2,B) :- phrase(get_var(List,B),[A2]).
get_var(List,get_var(A)) -->
{get_var(List,A_,A)},[A_].
get_var(List,B) -->
{member(B:A2,List)},[A2].
get_var(_,B) -->
{number(B)},[B].
get_var(List,(A+B)) -->
{get_var(List,A_,A), get_var(List,B_,B), A2 is A_ + B_},[A2].
get_var(List,(A-B)) -->
{get_var(List,A_,A), get_var(List,B_,B), A2 is A_ - B_},[A2].
get_var(List,(A/B)) -->
{get_var(List,A_,A), get_var(List,B_,B), A2 is A_ / B_},[A2].
get_var(List,(A*B)) -->
{get_var(List,A_,A), get_var(List,B_,B), A2 is A_ * B_},[A2].
get_var(List,(A mod B)) -->
{get_var(List,A_,A), get_var(List,B_,B), A2 is A_ mod B_},[A2].
get_var(List,(A>B)) -->
{get_var(List,A_,A), get_var(List,B_,B)},[A_ > B_].
get_var(List,(A<B)) -->
{get_var(List,A_,A), get_var(List,B_,B)},[A_ < B_].
get_var(List,(A,B)) -->
{get_var(List,A_,A), get_var(List,B_,B)},[(A_,B_)].
get_var(List,(A=B)) -->
{get_var(List,A_,A), get_var(List,B_,B)},[(A_=B_)].
get_var(List,(A;B)) -->
{get_var(List,A_,A), get_var(List,B_,B)},[(A_;B_)].
get_var(_,true) -->
[true].
get_var(_,false) -->
[false].
% code by #svick, modified to use dif/2 instead of (\=)/2
replaceP(_, _, [], []).
replaceP(O, R, [O|T], [R|T2]) :- replaceP(O, R, T, T2).
replaceP(O, R, [H|T], [H|T2]) :- dif(H,O), replaceP(O, R, T, T2).

A simple code snippet :
loop(M,N):-
between(M, N, X),
writeln(X),
X >= N, !.
loop(M,X).
Goal :
?- loop(5,10).
5
6
7
8
9
10

Well, I've made this simple program that implements a loop in Prolog:
:- initialization(main).
loop(I, End) :-
I > End;
writeln(I), Ii is I + 1, loop(Ii, End).
main :- loop(0, 10).
It basically prints numbers from 0 to 10 (inclusive).

Here's how i did it(using recursion) :
for(X , Y , Z):-
X<Y,
X1 is X+Z,
writeln("Hello"),
for(X1 , Y , Z).
nestedFor(X , Y , Z):-
X<Y,
X1 is X+Z,
not(for(0 , 10 , 1)),
writeln("World!"),
nestedFor(X1 , Y , Z).
Keep adding more functions to create more loops.

Related

Prolog - Backtracking through a set of dynamic options

I'm trying to trigger backtracking on a goal but in a dynamic way, if it's possible. To better exemplify my issue let's say we have the following PROLOG code:
num(1).
num(2).
num(3).
num(4).
num(5).
Then I head to SWI-Prolog and call: num(X). This triggers backtracking looking for all solutions, by typing ; .
What I would like is to remove those facts (num(1),num(2), etc) and replace that code with something thata generates those facts dynamically. Is there any way in which I can achieve this? Someting of the sorts,maybe?
num(X):- for X in 1..5
that yields the same solutions as the code above?
As far as I know, the findall predicate returns a list, which is not what I'm looking for. I would like to backtrack through all answers and look through them using ; in the console.
Yes there is, and you were already very close!
:- use_module(library(clpfd)).
num(X) :-
X in 1..5.
?- num(X).
X in 1..5.
?- num(X), X #>3.
X in 4..5.
?- num(X), labeling([], [X]).
X = 1
; X = 2
; X = 3
; X = 4
; X = 5.
SWI-Prolog has the (non-ISO) predicate between/3 for that:
num(X) :- between(1, 5, X).
You can implement the predicate (for other Prologs and for further tweaking) like this:
between2(A, A, A) :- !. % green cut
between2(A, B, A) :- A < B.
between2(A, B, C) :-
A < B,
A1 is A + 1,
between2(A1, B, C).
The signature for both between/3 and between2/3 is (+From,+To,?X). It means that the From and To must be bound and X can be either bound or not. Also note that From and To must be integers such that From <= To. (Oh, and these integers must be written using Arabic numerals with an optional plus or minus sign before. And using ASCII. Is something non-obvious still missed? And the integers must not be too large or too small, although SWI-Prolog is usually compiled with unbounded integer support, so both between(1, 100000000000000000000000000000000000000000000, X) and between2(1, 100000000000000000000000000000000000000000000, X) usually work.)

What is the difference in execution if the cut '!' is present?

counter([],[]).
counter([H|T],[[H,C1]|R]) :- counter(T,[[H,C]|R]),!, C1 is C+1.
counter([H|T],[[H,1]|R]) :- counter(T,R).
What is the effect of the "!" as I'm getting the same output for an input in both the above and below code?
counter([],[]).
counter([H|T],[[H,C1]|R]) :- counter(T,[[H,C]|R]),C1 is C+1.
counter([H|T],[[H,1]|R]) :- counter(T,R).
I'm new to Prolog.
What is the effect of the "!"
The cut prunes the search space. That is, in an otherwise pure and monotonic program, the cut will remove some solutions or answers. As long as those are redundant that's fine. It sounds so innocent and useful, doesn't it? Let's have a look!
And lest I forget, using [E,Nr] to denote pairs is rather unusual, better use a pair E-Nr.
We will now compare counter_cut/2 and counter_sans/2.
| ?- counter_cut([a,a],Xs).
Xs = [[a,2]].
| ?- counter_sans([a,a],Xs).
Xs = [[a, 2]]
; Xs = [[a, 1], [a, 1]]. % <<< surprise !!!
So the cut-version has fewer solutions. Seems the solution counter_cut/2 retained is the right one. In this very particular case. Will it always take the right one? I will try a minimally more general query:
| ?- counter_cut([a,B],Xs).
B = a,
Xs = [[a, 2]].
| ?- counter_sans([a,B],Xs).
B = a,
Xs = [[a, 2]]
; Xs = [[a, 1], [B, 1]].
Again, _sans is chattier, and this time, it is even a bit right-er; for the last answer includes B = b. In other words,
| ?- counter_cut([a,B], Xs), B = b.
fails. % incomplete !
| ?- counter_sans([a,B], Xs), B = b.
B = b,
Xs = [[a,1],[b,1]].
So sometimes the _cut version is better, and sometimes _sans. Or to put more directly: Both are wrong somehow, but the _sans-version at least includes all solutions.
Here is a "purified" version, that simply rewrites the last rule into two different cases: One for the end of the list and the other for a further, different element.
counter_pure([],[]).
counter_pure([H|T],[[H,C1]|R]) :- counter_pure(T,[[H,C]|R]), C1 is C+1.
counter_pure([H],[[H,1]]).
counter_pure([H,D|T],[[H,1]|R]) :- dif(H,D), counter_pure([D|T],R).
From an efficiency viewpoint that is not too famous.
Here is a test case for efficiency for a system with rational tree unification:
?- Es = [e|Es], counter(Es, Dict).
resource_error(stack).
Instead, the implementation should loop smoothly, at least till the end of this universe. Strictly speaking, that query has to produce a resource error, but only after it has counted up to a number much larger than 10^100000000.
Here's my pure and hopefully efficient solution:
counter([X|L], C):- counter(L, X, 1, C).
counter([],X, Cnt, [[X,Cnt]]).
counter([Y|L], X, Cnt, [[X,Cnt]|C]):-
dif(X, Y),
counter(L, Y, 1, C).
counter([X|L],X, Cnt, [[X,XCnt]|C]):-
Cnt1 #= Cnt+1,
Cnt1 #=< XCnt,
counter(L, X, Cnt1, [[X,XCnt]|C]).
Using if_3 as suggested by #false:
counter([X|L], C):- counter(L, X, 1, C).
counter([],X, Cnt, [[X,Cnt]]).
counter([Y|L], X, Cnt, [[X,XCnt]|C]):-
if_(X=Y,
(
Cnt1 #= Cnt+1,
Cnt1 #=< XCnt,
counter(L, X, Cnt1, [[X,XCnt]|C])
),
(
XCnt=Cnt,
counter(L, Y, 1, C)
)
).
The cut operator ! commits to the current derivation path by pruning all choice points. Given some facts
fact(a).
fact(b).
you can compare the answers with and without cut:
?- fact(X).
X = a ;
X = b.
?- fact(X), !.
X = a.
As you can see, the general query now only reports its first success. Still, the query
?- fact(b), !.
true.
succeeds. This means, that cut violates the interpretation of , as logical conjunction:
?- X = b, fact(X), !.
X = b.
?- fact(X), !, X=b.
false.
but from our understanding of conjunction, A ∧ B should hold exactly when B ∧ A holds. So why do this at all?
Efficiency: cuts can be used such that they only change execution properties but not the answers of a predicate. These so called green cuts are for instance described in Richard O'Keefe's Craft of Prolog. As demonstrated above, maintaining correctness of a predicate with cut is much harder than one without, but obviously, correctness should come before efficiency.
It looks as if your problem was green, but I am not 100% sure if there is not a change in the answers.
Negation: logical negation according to the closed world assumption is expressed with cut. You can define neg(X) as:
neg(X) :-
call(X),
!,
false.
neg(_) :-
true.
So if call(X) succeeds, we cut the choice point for the second rule away and derive false. Otherwise, nothing is cut and we derive true. Please be aware that this is not negation in classical logic and that it suffers from the non-logical effects of cut. Suppose you define the predicate land/1 to be one of the continents:
land(africa).
land(america).
land(antarctica).
land(asia).
land(australia).
land(europe).
and then define water as everything not on land:
water(X) :-
neg(land(X)).
then you can correctly obtain:
?- water(pacific).
true.
?- water(africa).
false.
But you can also derive:
?- water(space).
true.
which should not hold. In particular, in classical logic:
land(africa) ∧
land(america) ∧
land(antarctica) ∧
land(asia) ∧
land(australia) ∧
land(europe) → ¬ land(space).
is not valid. Again, you should know well what you are doing if you use negation in Prolog.
Here is my attempt using if_/3:
counter([], []).
counter([H|T], [[H,C]|OutT] ):-
if_(
T=[],
(C = 1,OutT=[]),
(
[H|T] = [H,H1|T2],
if_(
H=H1,
(counter([H1|T2], [[H1,C1]|OutT]), C is C1+1),
(C = 1, counter([H1|T2], OutT))
)
)
).

List indexes on a recursive program?

I've been searching for something that might help me with my problem all over the internet but I haven't been able to make any progress. I'm new to logic programming and English is not my first language so apologize for any mistake.
Basically I want to implement this prolog program: discord/3 which has arguments L1, L2 lists and P where P are the indexes of the lists where L1[P] != L2[P] (in Java). In case of different lengths, the not paired indexes just fail. Mode is (+,+,-) nondet.
I got down the basic case but I can't seem to wrap my head around on how to define P in the recursive call.
discord(_X,[],_Y) :-
fail.
discord([H1|T1],[H1|T2],Y) :-
???
discord(T1,T2,Z).
discord([_|T1],[_|T2],Y) :-
???
discord(T1,T2,Z).
The two clauses above are what I came up to but I have no idea on how to represent Y - and Z - so that the function actually remembers the length of the original list. I've been thinking about using nth/3 with eventually an assert but I'm not sure where to place them in the program.
I'm sure there has to be an easier solution although. Thanks in advance!
You can approach this in two ways. First, the more declarative way would be to enumerate the indexed elements of both lists with nth1/3 and use dif/2 to ensure that the two elements are different:
?- L1 = [a,b,c,d],
L2 = [x,b,y,d],
dif(X, Y),
nth1(P, L1, X),
nth1(P, L2, Y).
X = a, Y = x, P = 1 ;
X = c, Y = y, P = 3 ;
false.
You could also attempt to go through both list at the same time and keep a counter:
discord(L1, L2, P) :-
discord(L1, L2, 1, P).
discord([X|_], [Y|_], P, P) :-
dif(X, Y).
discord([_|Xs], [_|Ys], N, P) :-
succ(N, N1),
discord(Xs, Ys, N1, P).
Then, from the top level:
?- discord([a,b,c,d], [a,x,c,y], Ps).
Ps = 2 ;
Ps = 4 ;
false.

how can simulate nested loop in prolog?

how can i simulate this code in Prolog?
// L = an existing list ;
// function foo(var X, var Y)
result = new List();
for(int i=0;i<L.length;i++)
for(int j=0;j<L.length;j++){
result.add(foo(L.get(i), L.get(j));
}
nested loops are basically joins between sequences, and most of lists processing in Prolog is best expressed without indexing:
?- L=[a,b,c], findall(foo(X,Y), (member(X,L),member(Y,L)), R).
L = [a, b, c],
R = [foo(a, a), foo(a, b), foo(a, c), foo(b, a), foo(b, b), foo(b, c), foo(c, a), foo(c, b), foo(..., ...)].
edit
Sometime integers allow to capture the meaning in a simple way. As an example, my solution for one of the easier of Prolog context quizzes.
icecream(N) :-
loop(N, top(N)),
left, loop(N+1, center), nl,
loop(N+1, bottom(N)).
:- meta_predicate loop(+, 1).
loop(XH, PR) :-
H is XH,
forall(between(1, H, I), call(PR, I)).
top(N, I) :-
left, spc(N-I+1), pop,
( I > 1
-> pop,
spc(2*(I-2)),
pcl
; true
),
pcl, nl.
bottom(N, I) :-
left, spc(I-1), put(\), spc(2*(N-I+1)), put(/), nl.
center(_) :- put(/), put(\).
left :- spc(4).
pop :- put(0'().
pcl :- put(0')).
spc(Ex) :- V is Ex, forall(between(1, V, _), put(0' )).
Running in SWI-Prolog:
?- icecream(3).
()
(())
(( ))
/\/\/\/\
\ /
\ /
\ /
\/
true.
?- forall(loop(3,[X]>>loop(2,{X}/[Y]>>writeln(X-Y))),true).
1-1
1-2
2-1
2-2
3-1
3-2
true.
You can define a forto/4 meta-predicate easily. An example, taken from the Logtalk library loop object:
:- meta_predicate(forto(*, *, *, 0)).
forto(Count, FirstExp, LastExp, Goal) :-
First is FirstExp,
Last is LastExp,
forto_aux(Count, First, Last, 1, Goal).
:- meta_predicate(forto_aux(*, *, *, *, 0)).
forto_aux(Count, First, Last, Increment, Goal) :-
( First =< Last ->
\+ \+ (Count = First, call(Goal)),
Next is First + Increment,
forto_aux(Count, Next, Last, Increment, Goal)
; true
).
Example goal:
?- loop::forto(I, 1, 2, loop::forto(J, 1, 3, (write(I-J), nl))).
1-1
1-2
1-3
2-1
2-2
2-3
true.
Some Prolog compilers also provide built-in or library support for "logical loops" with good expressive power. Examples are (in alphabetic order) B-Prolog, ECLiPSe, and SICStus Prolog. Check the documentation of those systems for details. If you need a portable solution across most Prolog systems, check Logtalk's library documentation. Or simply take the above examples and define your own loop meta-predicates.
you can use this predicate using SICStus-prolog for looping variables I,J until N and get all of them inside fact foo/2 mentioned below successively ;
Code
loop(N) :- for(I,0,N),param(N) do
for(J,0,N),param(I) do
write(foo(I,J)),nl.
Result
| ?- loop(2).
foo(0,0)
foo(0,1)
foo(0,2)
foo(1,0)
foo(1,1)
foo(1,2)
foo(2,0)
foo(2,1)
foo(2,2)
yes

Finding the max in a list - Prolog

I was just introduced to Prolog and am trying to write a predicate that finds the Max value of a list of integers. I need to write one that compares from the beginning and the other that compares from the end. So far, I have:
max2([],R).
max2([X|Xs], R):- X > R, max2(Xs, X).
max2([X|Xs], R):- X <= R, max2(Xs, R).
I realize that R hasn't been initiated yet, so it's unable to make the comparison. Do i need 3 arguments in order to complete this?
my_max([], R, R). %end
my_max([X|Xs], WK, R):- X > WK, my_max(Xs, X, R). %WK is Carry about
my_max([X|Xs], WK, R):- X =< WK, my_max(Xs, WK, R).
my_max([X|Xs], R):- my_max(Xs, X, R). %start
other way
%max of list
max_l([X],X) :- !, true.
%max_l([X],X). %unuse cut
%max_l([X],X):- false.
max_l([X|Xs], M):- max_l(Xs, M), M >= X.
max_l([X|Xs], X):- max_l(Xs, M), X > M.
Ignoring the homework constraints about starting from the beginning or the end, the proper way to implement a predicate that gets the numeric maximum is as follows:
list_max([P|T], O) :- list_max(T, P, O).
list_max([], P, P).
list_max([H|T], P, O) :-
( H > P
-> list_max(T, H, O)
; list_max(T, P, O)).
A very simple approach (which starts from the beginning) is the following:
maxlist([],0).
maxlist([Head|Tail],Max) :-
maxlist(Tail,TailMax),
Head > TailMax,
Max is Head.
maxlist([Head|Tail],Max) :-
maxlist(Tail,TailMax),
Head =< TailMax,
Max is TailMax.
As you said, you must have the variables instantiated if you want to evaluate an arithmetic expression. To solve this, first you have to make the recursive call, and then you compare.
Hope it helps!
As an alternative to BLUEPIXY' answer, SWI-Prolog has a builtin predicate, max_list/2, that does the search for you. You could also consider a slower method, IMO useful to gain familiarity with more builtins and nondeterminism (and then backtracking):
slow_max(L, Max) :-
select(Max, L, Rest), \+ (member(E, Rest), E > Max).
yields
2 ?- slow_max([1,2,3,4,5,6,10,7,8],X).
X = 10 ;
false.
3 ?- slow_max([1,2,10,3,4,5,6,10,7,8],X).
X = 10 ;
X = 10 ;
false.
edit
Note you don't strictly need three arguments, but just to have properly instantiated variables to carry out the comparison. Then you can 'reverse' the flow of values:
max2([R], R).
max2([X|Xs], R):- max2(Xs, T), (X > T -> R = X ; R = T).
again, this is slower than the three arguments loops, suggested in other answers, because it will defeat 'tail recursion optimization'. Also, it does just find one of the maxima:
2 ?- max2([1,2,3,10,5,10,6],X).
X = 10 ;
false.
Here's how to do it with lambda expressions and meta-predicate foldl/4, and, optionally, clpfd:
:- use_module([library(lambda),library(apply),library(clpfd)]).
numbers_max([Z|Zs],Max) :- foldl(\X^S^M^(M is max(X,S)),Zs,Z,Max).
fdvars_max( [Z|Zs],Max) :- foldl(\X^S^M^(M #= max(X,S)),Zs,Z,Max).
Let's run some queries!
?- numbers_max([1,4,2,3],M). % integers: all are distinct
M = 4. % succeeds deterministically
?- fdvars_max( [1,4,2,3],M).
M = 4. % succeeds deterministically
?- numbers_max([1,4,2,3,4],M). % integers: M occurs twice
M = 4. % succeeds deterministically
?- fdvars_max( [1,4,2,3,4],M).
M = 4. % succeeds deterministically
What if the list is empty?
?- numbers_max([],M).
false.
?- fdvars_max( [],M).
false.
At last, some queries showing differences between numbers_max/2 and fdvars_max/2:
?- numbers_max([1,2,3,10.0],M). % ints + float
M = 10.0.
?- fdvars_max( [1,2,3,10.0],M). % ints + float
ERROR: Domain error: `clpfd_expression' expected, found `10.0'
?- numbers_max([A,B,C],M). % more general use
ERROR: is/2: Arguments are not sufficiently instantiated
?- fdvars_max( [A,B,C],M).
M#>=_X, M#>=C, M#=max(C,_X), _X#>=A, _X#>=B, _X#=max(B,A). % residual goals
list_max([L|Ls], Max) :- foldl(num_num_max, Ls, L, Max).
num_num_max(X, Y, Max) :- Max is max(X, Y).
%Query will be
?-list_max([4,12,5,3,8,90,10,11],Max).
Max=90
Right now I was working with recursion in Prolog, so if it is useful for someone I will leave 'my two cents' solving it in the two ways that I have thought:
% Start
start :- max_trad([2, 4, 6, 0, 5], MaxNumber1),
max_tail([2, 4, 6, 0, 5], 0, MaxNumber2),
show_results(MaxNumber1, MaxNumber2).
% Traditional Recursion (Method 1)
max_trad([Head|Tail], Max) :- max_trad(Tail, Value), Head > Value, Max is Head.
max_trad([Head|Tail], Max) :- max_trad(Tail, Value), Head =< Value, Max is Value.
max_trad([], 0).
% Tail Recursion (Method 2)
max_tail([], PartialMax, PartialMax).
max_tail([Head|Tail], PartialMax, FinalMax) :- Head > PartialMax, max_tail(Tail, Head, FinalMax).
max_tail([_|Tail], PartialMax, FinalMax) :- max_tail(Tail, PartialMax, FinalMax).
% Show both of the results
show_results(MaxNumber1, MaxNumber2) :-
write("The max value (obtained with traditional recursion) is: "), writeln(MaxNumber1),
write("The max value (obtained with tail recursion) is: "), writeln(MaxNumber2).
The output of the above code is:
Both methods are similar, the difference is that in the second an auxiliary variable is used in the recursion to pass values forward, while in the first method, although we have one less variable, we are filling the Stack with instructions to be executed later, so if it were an exaggeratedly large list, the second method is appropriate.
maximum_no([],Max):-
write("Maximum No From the List is:: ",Max).
maximum_no([H|T],Max):-
H>Max,
N = H,
maximum_no(T,N).
maximum_no(L,Max):-
maximum_no(L,Max).
The maximum number in a list in Prolog ?
max([],A):-print(A),!.
max([Head | Tail] , A):-A =< Head ,A1 is Head , max(Tail,A1) ; max(Tail,A).
max(L,M):-
member(M,L),
findall(X,(member(X,L),X>M),NL),
length(NL,0).

Resources