I trying to develop a small program in Prolog. Currently, I'm starting with Prolog and therefore there are issues that I do not understand well.
My program pretend to count the number of occurrences of an element in a list. In the end, it must to show next message: "Element X occurrs N times."
The code is as given below:
count_occur(X, [], N) :- format("Element ~d occurrs ~d times. ~n", [X,N]).
count_occur(X, [X|T], N) :-
count_occur(X, T, N2),
N is N2 + 1.
count_occur(X, [Y|T], N) :-
X \= Y,
count_occur(X, T, N).
Consulting with an example I always get following error:
?- count_occur(5,[2, 5, 5, 5, 6, 6, 8, 9, 9, 9], 0).
Element 5 ocurrs
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [19] format("Element ~d ocurrs ~d times. ~n",[5,_8398])
ERROR: [18] count_occur(5,[],_8428) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:1
ERROR: [11] count_occur(5,[5,6|...],_8456) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:3
ERROR: [10] count_occur(5,[5,5|...],_8496) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:3
ERROR: [9] count_occur(5,[5,5|...],0) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:3
ERROR: [7] <user>
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
I am using third params like counter but in the case base Prolog does not know the value of N.
If you insist on having that message printed, I would suggest to at least separate the output from the predicate describing the actual relation. Consider something along this pattern:
calling_predicate(...) :-
other_predicate(...), % <- predicate describing the actual relation
format(...). % <- output
You could, for instance, substitute count_occur/3 for calling_predicate and count_occur_/3 from #User9213's post for other_predicate. Alternatively you could opt for using CLP(FD) as suggested by #mat. Consider for example the following version using if_/3:
:- use_module(library(clpfd)).
count_occur(X, L, N) :-
list_x_count_(L,X,N,0), % <- actual relation
format("Element ~w occurs ~d times. ~n", [X,N]). % <- output
list_x_count_([],_X,N,N).
list_x_count_([Y|Ys],X,N,N0) :-
if_(Y=X,(N0 #< N, N1 #= N0+1), N1 #= N0),
list_x_count_(Ys,X,N,N1).
Since the elements in the list are not necessarily numbers, it is opportune to use the escape sequence ~w for the argument X instead of ~d (see the documentation of format/2 for more detail). If you query that with your given example, you get the desired result:
?- count_occur(5,[2,5,5,5,6,6,8,9,9,9], N).
Element 5 occurs 3 times.
N = 3.
Note that this query succeeds deterministically. That is, there are no superfluous choicepoints left, hence you don't need to enter ; after Prolog tells you the only answer. The example queries provided by #mat and #lambda.xy.x in the comments work as well:
?- count_occur(1,[2,X],0).
Element 1 occurs 0 times.
dif(X, 1).
?- count_occur(a, [a,b,c], N).
Element a occurs 1 times.
N = 1.
?- count_occur(X, [a,b,c], N).
Element a occurs 1 times.
X = a,
N = 1 ;
Element b occurs 1 times.
X = b,
N = 1 ;
Element c occurs 1 times.
X = c,
N = 1 ;
Element _G210 occurs 0 times.
N = 0,
dif(X, c),
dif(X, b),
dif(X, a).
I don't know how it can work like you have written it. Maybe write it like that:
count_occur(X, L, N) :- count_occur_(L, X, N).
count_occur_([], _, 0). % the 0 here is important (why?)
count_occur_([X|Xs], X, N) :-
count_occur_(Xs, X, N0),
succ(N0, N).
count_occur_([Y|Ys], X, N) :-
dif(Y, X),
count_occur_(Ys, X, N).
I found the error. The solution is:
count_occur(X, [], N) :- format("Element ~d occurrs ~d times. ~n", [X,N]).
count_occur(X, [X|T], N) :-
N2 is N + 1,
count_occur(X, T, N2).
count_occur(X, [Y|T], N) :-
X \= Y,
count_occur(X, T, N).
Second count_occur statement was wrong and it was not incrementing adequately.
Related
The predicate draw/2 with argument N and M should draw up to M stars and should increase N until N > 5. Example: draw(3,5) =>
***
****
*****
My problem is that my code only draw up to four stars, so:
***
****
Why does that happen when there is a M1 =< N condition in draw/2?
line(0,_) :- nl.
line(X, Symbol) :-
write(Symbol),
Line is X - 1,
line(Line, Symbol).
% b)
draw(N, N).
draw(M, N) :-
line(M, '*'),
M1 is M + 1,
M1 =< N,
draw(M1, N).
The problem is that the first clause of draw/2, draw(N, N). succeeds before you even get to the condition in the second clause.
But it would be much easier to do this whole exercise using between/3 since it counts the prolog way (both lower and upper limit included). Here are some examples:
?- between(3, 5, X).
X = 3 ;
X = 4 ;
X = 5.
?- forall(between(3, 5, X), format("~d~n", [X])).
3
4
5
true.
?- forall(between(3, 5, X), ( forall(between(1, X, _), write(*) ), nl )).
***
****
*****
true.
If you don't like one-liners you can define:
draw(N, M) :-
forall(between(N, M, X),
line(X)).
line(X) :-
forall(between(1, X, _),
write(*)),
nl.
You should most definitely avoid counting on your own. Because there are two hard things in programming and the third one is off-by-one errors.
With SWI-Prolog you can also use a format hack to print the necessary number of stars directly:
?- forall(between(3, 7, X), format("~`*t~*|~n", [X])).
***
****
*****
******
*******
true.
It is somehow documented why this works.
Note: the forall/2 predicate is defined as \+ ( Cond, \+ Action ). So you could rewrite the last without forall, directly as:
?- \+ ( between(3, 5, X), \+ format("~`*t~*|~n", [X]) ).
***
****
*****
true.
This itself could be re-written as a "failure loop", but this has some downsides.
?- ( between(3, 5, X), % generate solutions for X = 3 ; 4 ; 5
format("~`*t~*|~n", [X]), % side effect
fail % fail to backtrack to the next solution
; true % when there are no more solutions, succeed
).
***
****
*****
true.
For example, a failure of the side-effect in a fail driven loop causes it to fail (see the forall/2 docs). Compare:
?- ( between(3, 5, X), fail, fail ; true ).
true.
?- forall(between(3, 5, X), fail).
false.
?- \+ ( between(3, 5, X), \+ fail ).
false.
If you want to count up, you might want to take a look at the definition of a library predicate that has similar functionality: numlist/3.
If you take only the logic in numlist_/3, drop the last argument and instead directly use the value to print a line, you get:
draw(U, U) :-
!,
line(U).
draw(L, U) :-
line(L),
L2 is L+1,
draw(L2, U).
You will need to add the argument checking however. You could do it like this:
line(0) :-
!,
nl.
line(X) :-
succ(X0, X),
write(*),
line(X0).
draw(L, U) :-
L =:= U,
!,
line(U).
draw(L, U) :-
L < U,
line(L),
L2 is L+1,
draw(L2, U).
I tried this to solve problem of splitting list in lists of length 2^0, 2^2, 2^3 ... 2^n
split(L, X) :- split(L, 1, X).
split(X, N, [X]) :-
length(X, L),
L < N.
split(L, N, [X|Xs]) :-
length(X, N),
M = N * 2,
append(X, R, L),
split(R, M, Xs).
but I have problem:
ERROR: Type error: integer' expected, found1*2' (a compound)
ERROR: In:
ERROR: [12] throw(error(type_error(integer,...),context(...,_9654)))
I'm using SWI-Prolog and have no clue how to fix it. I will really appreciate if you could help me
I want to get the length for the maximum sequence of even numbers but i get this error ERROR: >/2: Arguments are not sufficiently instantiated. I read something online but I can't understand.
Example:
max([2,4,6,7,4,8],R).
R=3
Here is my code:
max([H|T], L) :- max1(H, 1, T, L).
max1(H,_, [],0):-
H mod 2 =:=1.
max1(H, N, [], N):-
H mod 2 =:=0.
max1(X, N, [H|T], L) :-
X mod 2 =:=0,
M is N+1,
max1(H, M, T, L).
max1(X,N,[H|T],L):-
X mod 2 =:=1,
M>N,
max1(H, 1, T, M).
max1(X,N,[H|T],L):-
X mod 2 =:=1,
N>M,
max1(H,1,T,N).
In your last predicate max1, M isn't meaning anything. And in the predicate above you have the same problem because on the moment you are comparing M>N, M is also unknown.
I also don't understand why you are decoupling your list into X instead if immediately using [H|T]. Which simplifies the program.
Here is a solution that works with an accumulator.
max(L, R) :-
maxAcc(L, 0, 0, R). % list, currentBest, currentTot, Acc
maxAcc([],_, Best, Best).
maxAcc([H|T],Cur, Best, Acc) :-
H mod 2 =:=0,
CurN is Cur+1,
BestNext is max(CurN,Best),
maxAcc(T, CurN, BestNext, Acc).
maxAcc([H|T],Cur, Best, Acc) :-
H mod 2 =:=1,
BestNext is max(Cur,Best),
maxAcc(T, 0, BestNext, Acc).
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 calculate the Fibonacci series using the following function:
fib(0,A,_,A).
fib(N,A,B,F) :-
N1 is N-1, Sum is A+B, fib(N1, B, Sum, F).
fib(N, F) :- fib(N, 0, 1, F).
This is intended to works like this:
| ?- fib(20,Result).
Result = 6765 ?
But when I try this, it complains:
| ?- fib(What,6765).
uncaught exception: error(instantiation_error,(is)/2)
Does anyone understand why this is happening?
In the second clause:
fib(N,A,B,F) :-
N1 is N-1, Sum is A+B, fib(N1, B, Sum, F).
N is a variable to be decremented, and in your call to:
fib(What, 6765).
The variable is not yet defined, so you get the instantiation error on N1 is N - 1.
In swipl I do even get the error:
?- fib(W, 6765).
ERROR: fib/4: Arguments are not sufficiently instantiated
Now that you know it's an error, do you mind to know if it's actually possible to answer your query?
How do you would approach the problem? Your function it's ok, isn't it? Exactly, because it's a function, and not a relation, you get the error.
It's a bit complicate to solve it, but CLP can do !
See this fascinating example from CLP(FD) documentation (cited here)
:- use_module(library(clpfd)).
n_factorial(0, 1).
n_factorial(N, F) :-
N #> 0, N1 #= N - 1, F #= N * F1,
n_factorial(N1, F1).
We need something like this, but for fibonacci.
See how easy it is:
:- [library(clpfd)].
fib(0,A,_,A).
fib(N,A,B,F) :-
N #> 0,
N1 #= N-1,
Sum #= A+B,
fib(N1, B, Sum, F).
fib(N, F) :- fib(N, 0, 1, F).
i.e. replace is/2 by #=/2 and we get
?- fib(20,Result).
Result = 6765 .
?- fib(X,6765).
X = 20 ;
^C
note, after the first response the program loops!
Do you a see a way to correct it? Or another question could be worth...
A more clear and more natural predicate definition may be:
//The two base steps
fib1(0,0).
fib1(1,1).
//the recursive step
fib1(N,F) :-
N >= 0, M is N-2, O is N-1, fib1(M,A), fib1(O,B), F is A+B.
It is also a definition with only one predicate: fib/2