As a beginner, I am trying to solve a matrix problem, in which the solution is either the summation or the multiplication of the distinct digit in the matrix. For example,[[14,_,_,_],[15,_,_,_],[28,_,1,_]]. The predicate should generate the solution according to the matrix. However, I bumped into a problem that my combined predicate failed, but each of them succeeded independently.
I broke the problem down to summation and multiplication. Therefore, using clpfd library, and some predicates, for summation:
removeHead([Head|Tail],Tail).
get_head_element([],_).
get_head_element([Head|Rest],Head).
solve_sum(Row,RestRow):-
get_head_element(Row, Goal),
removeHead(Row,RestRow),
RestRow ins 1..9,
all_distinct(RestRow),
sum(RestRow, #=, Goal).
For multiplication:
multiply(List,Result):-
multiply(List,1,Result).
multiply([Element|RestList],PrevResult,Result):-
NextResult #= PrevResult * Element,
multiply(RestList,NextResult, Result).
multiply([], Result, Result).
solve_multiply(Row,RestRow):-
get_head_element(Row, Goal),
removeHead(Row,RestRow),
RestRow ins 1..9,
multiply(RestRow,Goal),
all_distinct(RestRow).
Both solve_sum and solve_multiply works for a single row, but here I combine these two predicates to:
solve_row_sum_or_multiply([],_).
solve_row_sum_or_multiply([HeadRow|Matrix],Solution):-
maplist(all_distinct,Matrix),
get_head_element(HeadRow,Goal),
( Goal >= 25
-> solve_multiply(HeadRow,Solution),
write(Solution)
; ( solve_sum(HeadRow,Solution),
write(Solution)
; solve_multiply(HeadRow,Solution),
write(Solution))
),solve_row_sum_or_multiply(Matrix,Solution).
When I use the solve_row_sum_or_multiply([[14,_,_,_],[15,_,_,_],[28,_,_,_]],X), it will give me the possible combinations. However, when solve_row_sum_or_multiply([[14,_,_,_],[15,_,_,_],[28,_,1,_]],X), it gave me false, but there's a solution possible there, such as [[14,7,2,1],[15,3,7,5],[28,4,1,7]].
I am wondering what could be wrong. Any help is highly appreciated!
EDIT
The problem is inside the combined predicate, and it's better to write the predicate which the answer suggests instead of a nested if-then-else predicate.
Let's review this code.
intro code
:- use_module(library(clpfd)).
% ---
% Make sure you see all the information in a list printed at the
% toplevel, i.e. tell the toplevel to not elide large lists (print
% them in full, don't use '...')
% ---
my_print :-
Depth=100,
Options=[quoted(true), portray(true), max_depth(Depth), attributes(portray)],
set_prolog_flag(answer_write_options,Options),
set_prolog_flag(debugger_write_options,Options).
:- my_print.
multiply/2
Recode the multiply/2 predicate so that it can be read more easily. Add test code to make sure it actually does what we think it does:
% ---
% Set up constraint: all the elements in List, multiplied
% together, must yield Result. If the List is empty, the
% Result must be 1.
% ---
multiply(Factors,Product):-
multiply_2(Factors,1,Product).
multiply_2([Factor|Factors],PartialProduct,Product):-
PartialProduct2 #= PartialProduct * Factor,
multiply_2(Factors,PartialProduct2,Product).
multiply_2([],Product,Product).
solve_multiply([Product|Factors]):-
Factors ins 1..9,
multiply(Factors,Product),
all_distinct(Factors).
% ---
% Testing
% ---
:- begin_tests(multiply).
test(1) :-
multiply([X,Y,Z],6),
[X,Y,Z] ins 1..9,
X #=< Y, Y #=< Z,
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1, 1, 6], [1, 2, 3]]).
test(2) :-
multiply([],Result),
assertion(Result == 1).
test(3) :-
multiply([X,Y],3),
[X,Y] ins 1..9,
X #=< Y,
bagof([X,Y],label([X,Y]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,3]]).
test(4) :-
solve_multiply([6,X,Y,Z]),
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]).
test(5) :-
solve_multiply([362880,F1,F2,F3,F4,F5,F6,F7,F8,F9]),
F1 #=< F2,
F2 #=< F3,
F3 #=< F4,
F4 #=< F5,
F5 #=< F6,
F6 #=< F7,
F7 #=< F8,
F8 #=< F9,
bagof([F1,F2,F3,F4,F5,F6,F7,F8,F9],label([F1,F2,F3,F4,F5,F6,F7,F8,F9]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,2,3,4,5,6,7,8,9]]).
test(6,fail) :-
solve_multiply([-1,X,Y,Z]).
:- end_tests(multiply).
solve_sum/1
For summation, after simplifying and re-coding to Prolog's "pattern matching" style instead of (for want of a better word) "Algol calling style" as is used in the original the question (which confused me greatly I have to say).
This looks ok too. Note that the predicate solve_sum/1 is quite different-in-argument-style from multiply/2 It is better - and easier on the reader (and oneself) - if one keeps the same calling conventions.
solve_sum([Sum|Terms]):-
Terms ins 1..9,
all_distinct(Terms),
sum(Terms, #=, Sum).
% ---
% Testing
% ---
:- begin_tests(sum).
test(0) :-
solve_sum([0]).
test(1) :-
solve_sum([6,X,Y,Z]),
X #=< Y, Y #=< Z,
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1, 2, 3]]).
test(2) :-
solve_sum([9,X,Y,Z]),
X #=< Y, Y #=< Z,
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,2,6],[1,3,5],[2,3,4]]).
test(3,fail) :-
solve_sum([1,_X,_Y,_Z]).
:- end_tests(sum).
A printing predicate to get nice results
Prolog makes it easy to construct arbitrary structures "on the fly", one just has to stipulate exactly how the structure shall look.
Our "solution" is:
A list
With each element of the list a "row" (standing for one of the expressions)
And the row a term: row(Result,Op,RowValues) where Result is the left-hand-side of an equation, Op is one of add or mult and RowValues is a list with the values found for the values in the equation.
print_solution([]).
print_solution([Labeling|Labelings]) :-
format("---~n"),
print_rows_of_solution(Labeling),
format("---~n"),
print_solution(Labelings).
print_rows_of_solution([]).
print_rows_of_solution([row(Result,Op,RowValues)|Rows]) :-
print_row(Result,RowValues,Op),
print_rows_of_solution(Rows).
print_row(Result,[RowEntry|RowEntries],Op) :-
format("~q = ~q",[Result,RowEntry]),
print_row_2(RowEntries,Op).
print_row_2([RowEntry|RowEntries],Op) :-
((Op == mult) -> OpChar = '*'
; (Op == add) -> OpChar = '+'
; OpChar = '?'),
format(" ~q ~q",[OpChar,RowEntry]),
print_row_2(RowEntries,Op).
print_row_2([],_) :-
format("~n").
solve_row_sum_or_multiply/2
This has been modified to also collect the operation selected in a second argument (a list).
Note that the "maplist-all-distinct over the matrix" is not done here because that seems wrong.
solve_row_sum_or_multiply([],[]).
solve_row_sum_or_multiply([Row|MoreRows],[mult|Ops]) :-
Row = [X|_Xs],
X >= 25,
solve_multiply(Row), % we now have imposed a product constraint on the current Row
solve_row_sum_or_multiply(MoreRows,Ops).
solve_row_sum_or_multiply([Row|MoreRows],[add|Ops]) :-
Row = [X|_Xs],
X < 25,
solve_sum(Row), % we now have imposed a sum constraint on the current Row
solve_row_sum_or_multiply(MoreRows,Ops).
solve_row_sum_or_multiply([Row|MoreRows],[mult|Ops]) :-
Row = [X|_Xs],
X < 25,
solve_multiply(Row), % alternatively, we now have imposed a product constraint on the current Row
solve_row_sum_or_multiply(MoreRows,Ops).
And finally a "main" predicate
In trial_run/1 we stipulate that all variables except X32 be distinct and that X32 be 1. If X32 were in the "distinct set", none of the variables could take on the value 1 - there is no solution in that case.
We also impose a sorting to get only a set of "canonical" solutions:
We collect all possible solutions for solving and labeling using bagof/3:
trial_run(Solutions) :-
all_distinct([X11,X12,X13,X21,X22,X23,X31,X33]),
X32=1,
X11 #=< X12, X12 #=< X13,
X21 #=< X22, X22 #=< X23,
X31 #=< X33,
% multiple solutions solving x labeling may exist; collect them all
bagof(
[
row(14,Op1,[X11,X12,X13]),
row(15,Op2,[X21,X22,X23]),
row(28,Op3,[X31,X32,X33])
],
(
solve_row_sum_or_multiply( [[14,X11,X12,X13],[15,X21,X22,X23],[28,X31,X32,X33]], [Op1,Op2,Op3] ),
label([X11,X12,X13,X21,X22,X23,X31,X32,X33])
),
Solutions).
Does it work?
Apparently yes, and there is only one solution:
?- trial_run(Solutions),print_solution(Solutions).
---
14 = 2 + 3 + 9
15 = 1 + 6 + 8
28 = 4 * 1 * 7
---
Solutions = [[row(14,add,[2,3,9]),row(15,add,[1,6,8]),row(28,mult,[4,1,7])]].
Related
I'm new in prolog, and I wanted to create a "function" to count how many different values I have in a list.
I've made this predicate to count the total number of values:
tamanho([],0).
tamanho([H|T],X) :- tamanho(T,X1), X is X1+1.
I wanted to follow the same line of thought like in this last predicate.(Don't know if that's possible).
So in a case where my list is [1,2,2,3], the answer would be 3.
Can someone give me a little help?
Here is a pure version which generalizes the relation. You can not only count but just see how elements have to look like in order to obtain a desired count.
In SWI, you need to install reif first.
:- use_module(library(reif),[memberd_t/3]).
:- use_module(library(clpz)). % use clpfd in SWI instead
:- op(150, fx, #). % backwards compatibility for old SWI
nt_int(false, 1).
nt_int(true, 0).
list_uniqnr([],0).
list_uniqnr([E|Es],N0) :-
#N0 #>= 0,
memberd_t(E, Es, T),
nt_int(T, I),
#N0 #= #N1 + #I,
list_uniqnr(Es,N1).
tamanho(Xs, N) :-
list_uniqnr(Xs, N).
?- tamanho([1,2,3,1], Nr).
Nr = 3.
?- tamanho([1,2,X,1], 3).
dif:dif(X,1), dif:dif(X,2).
?- tamanho([1,2,X,Y], 3).
X = 1, dif:dif(Y,1), dif:dif(Y,2)
; Y = 1, dif:dif(X,1), dif:dif(X,2)
; X = 2, dif:dif(Y,1), dif:dif(Y,2)
; Y = 2, dif:dif(X,1), dif:dif(X,2)
; X = Y, dif:dif(X,1), dif:dif(X,2)
; false.
You can fix your code by adding 1 to the result that came from the recursive call if H exists in T, otherwise, the result for [H|T] call is the same result for T call.
tamanho([],0).
tamanho([H|T], X) :- tamanho(T, X1), (member(H, T) -> X is X1; X is X1 + 1).
Tests
/*
?- tamanho([], Count).
Count = 0.
?- tamanho([1,a,21,1], Count).
Count = 3.
?- tamanho([1,2,3,1], Count).
Count = 3.
?- tamanho([1,b,2,b], Count).
Count = 3.
*/
In case the input list is always numerical, you can follow #berbs's suggestion..
sort/2 succeeds if input list has non-numerical items[1] so you can use it without any restrictions on the input list, so tamanho/2 could be just like this
tamanho(T, X) :- sort(T, TSorted), length(TSorted, X).
[1] thanks to #Will Ness for pointing me to this.
I'm trying to figure out how to create a predicate in prolog that sums the squares of only the even numbers in a given list.
Expected output:
?- sumsq_even([1,3,5,2,-4,6,8,-7], Sum).
Sum = 120 ;
false.
What I know how to do is to remove all the odd numbers from a list:
sumsq_even([], []).
sumsq_even([Head | Tail], Sum) :-
not(0 is Head mod 2),
!,
sumsq_even(Tail, Sum).
sumsq_even([Head | Tail], [Head | Sum]) :-
sumsq_even(Tail, Sum).
Which gives me:
Sum = [2, -4, 6, 8]
And I also know how to sum all the squares of the numbers in a list:
sumsq_even([], 0)
sumsq_even([Head | Tail], Sum) :-
sumsq_even(Tail, Tail_Sum),
Sum is Head * Head + Tail_Sum.
But I can't seem to figure out how to connect these two together. I'm thinking I may have gone the wrong way about it but I'm not sure how to define proper relationships to get it to make sense.
Thanks!
Split your problem into smaller parts. As you already said, you have two different functionalities that should be combined:
remove odd numbers from a list (even)
sum all the squares of the numbers in a list (sumsq)
So, in the first place, use different predicate names for different functionalities:
even([], []).
even([Head | Tail], Sum) :-
not(0 is Head mod 2),
!,
even(Tail, Sum).
even([Head | Tail], [Head | Sum]) :-
even(Tail, Sum).
sumsq([], 0).
sumsq([Head | Tail], Sum) :-
sumsq(Tail, Tail_Sum),
Sum is Head * Head + Tail_Sum.
In a third predicate you can now combine the two subsequent smaller steps:
sumsq_even(List, Sum) :-
even(List, Even_List),
sumsq(Even_List, Sum).
In this rule, first the (input) list is reduced to even elements (Even_List) and after that the sum of the squares are calculated.
This is the result for your example:
sumsq_even([1,3,5,2,-4,6,8,-7], Sum).
S = 120.
Using clpfd and Prolog lambda write:
:- use_module(library(clpfd)).
:- use_module(library(lambda)).
zs_sumevensq(Zs, S) :-
maplist(\Z^X^(X #= Z*Z*(1-(Z mod 2))), Zs, Es),
sum(Es, #=, S).
Sample query as given by the OP:
?- zs_sumevensq([1,3,5,2,-4,6,8,-7], S).
S = 120.
You can actually do both tasks (filtering the even number and summing them up) at once:
:- use_module(library(clpfd)).
nums_evensumsq([],0).
nums_evensumsq([X|Xs],S0) :-
X mod 2 #= 0,
nums_evensumsq(Xs,S1),
S0 #= S1 + X * X.
nums_evensumsq([X|Xs],S) :-
X mod 2 #= 1,
nums_evensumsq(Xs,S).
Querying the predicate gives the desired result:
?- nums_evensumsq([1,3,5,2,-4,6,8,-7],S).
S = 120 ? ;
no
You can write it even shorter using if_/3 as defined here:
nums_evensumsq([],0).
nums_evensumsq([X|Xs],S0) :-
nums_evensumsq(Xs,S1),
Y #= X mod 2,
if_(Y = 0, S0 #= S1 + X * X, S0 #= S1).
Note that the comparison in the first argument of if_/3 is done with =/3 as defined here.
Once you mastered the basics, you could be interested to learn about builtins. Library aggregate, provides a simple way to handle lists, using member/2 as list elements 'accessor':
sumsq_even(Ints, Sum) :-
aggregate(sum(C), I^(member(I, Ints), (I mod 2 =:= 0 -> C is I*I ; C = 0)), Sum).
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).
I am trying to write a Prolog (CLP) predicate that would build a constraint constraining inequality of two lists.
More formally, having two lists A=[A1,...,AN], B=[B1,...,BN] the constraint is defined as (A1 #\= B1) #\/ (A2 #\= B2) #\/ ... #\/ (AN #\= BN).
I am unsure how to build this constraint given two lists of arbitrary length. This is my attempt. I understand why it does not work, but can not fix it.
any_different([], []).
any_different([H1|T1], [H2|T2]):-
H1 #\= H2 #\/ any_different(T1, T2).
You'll want to build up the disjunction and return it through a third argument:
any_different([], [], V) :-
V #= 0. % no differences between [] and []
any_different([H1|T1], [H2|T2], Disj) :-
any_different(T1, T2, Disj0),
Disj #<==> (H1 #\= H2) #\/ Disj0.
Now, calling any_different(List1, List2, AnyDiff) contrains a variable AnyDiff that you can pass to the labeling predicate along with your other variables. By stating AnyDiff #= 0 you can constrain List1 and List2 to be equal, while AnyDiff #= 1 will cause them to be unequal.
I think that, at least in SWI-Prolog, the predicate dif/2 and library(clpfd) could be an alternative to the reification:
?- L=[X,Y,Z], L ins 1..3, dif(L,[1,2,3]), label(L).
L = [1, 1, 1],
X = Y, Y = Z, Z = 1 ;
L = [1, 1, 2],
X = Y, Y = 1,
Z = 2 ;
...
Here's an implementation based on sum/3 and clpfd reification (#<==>)/2:
not_equals_reified(X, Y, B) :-
X #\= Y #<==> B.
any_different(Xs, Ys) :-
maplist(not_equals_reified, Xs, Ys, Bs),
sum(Bs, #>, 0).
By using meta-predicate maplist/4 we don't even need to write recursive code!
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.