Calculate sum of marks

Hello, I’m just a beginner in Prolog Programming, and I have a question about the sum of marks that I have to then find the average. I don’t know how can I do it.


sum(S,M):- M1 is M+1, mark(M1), sum(S1,M1), S is mark(M1)+S1.

My error is

Arguments are not sufficiently instantiated
   [1] sum(_1616,_1618).

Please, help.

Doing math in Prolog is different than the way other programming languages do it.

While Prolog in theory and design is a programming language without static types at times it is easier if one thinks of certain syntax as having a type. In this case one should think of arithmetic expressions as being typed.

The next thing to understand about Prolog is that to evaluate an arithmetic expression the predicate is/2 is needed/often used.

An example arithmetic expression 3 + 18 + 10 and using that with is/2

?- is(Sum, 3 + 18 + 10).
Sum = 31.

or more commonly in code as

?- Sum is 3 + 18 + 10.
Sum = 31.

Now is is also infix operator

?- current_op(P,T,is).
P = 700,
T = xfx.

and since operators are rewritten as predicates when the code is loaded, they are converted from expressions (think string input) using operators into terms, think abstract syntax tree, E.g.

?- atom_to_term("3 + 18 + 10",Term,[]),write_canonical(Term).
Term = 3+18+10.

and to evaluate the term is/2 is used, E.g.

?- atom_to_term("3 + 18 + 10",Term,[]),write_canonical(Term),is(Sum,Term).
Term = 3+18+10,
Sum = 31.

Since your problem has some facts, a quick way to enter facts, predicates etc., at the top level is to just enter them directly into the user module (Reserved Modules) , E.g.

?- [user].
|: mark(3).
|: mark(18).
|: mark(10).
|:                  % Press Ctrl-D to exit 
% user://1 compiled 0.00 sec, 3 clauses

and to verify the facts are there using listing/1, E.g.

?- listing(mark).


To extract the values from the facts just use the fact functor, mark with a variable for the argument(s), E.g.

?- mark(Value).
Value = 3 ;
Value = 18 ;
Value = 10.

and one can collect the values into a list easily with findall/3, E.g.

?- findall(Value,mark(Value),Values).
Values = [3, 18, 10].

While one can use foldl/4 with plus/3 to sum the values in the list, E.g.

?- findall(Value,mark(Value),Values),foldl(plus,Values,0,Sum).
Values = [3, 18, 10],
Sum = 31.

in production code you might find findall/3 used with sum_list/2, E.g.

?- findall(Value,mark(Value),Values),sum_list(Values,Sum).
Values = [3, 18, 10],
Sum = 31.

or aggregate/3, E.g.

?- aggregate(sum(Value),mark(Value),Sum).
Sum = 31.

In many cases I like to think of findall/3 like select for SQL queries, it pulls in the data then leaves open the door for accessing the returned list. aggregate/3 on the other hand does not allow for repeated access to the list but is nice if only one predicate is executed on the list, e.g. sum.

I take that your question is a training problem and the use of higher order predicates is not allowed, so will leave the rest as an exercise, E.g. using recursion with base and recursive case predicates.

Yes, thank you.

Thank you very much.

I tried the the problem using some extra basics of Prolog. I do not intend
to recommend at all, but just in case if you are very curious person on how the sum is calculated from facts in Prolog without using advanced library.


summarks:- retractall(acc(_)),
	(	mark(X),
		Sum0 is  Sum + X,
	;	acc(TotalMark)
	format("Total Mark is ~w.~n", [TotalMark]).

% ?- summarks.
%@ Total Mark is 31.
%@ true.

A straightforward solution would be to use findall/3, sum_list/2 and length/2. Findall is a really handy predicate which finds all solutions to a goal (in your case mark(X)) and puts them in a list. Good luck!

OK, Thank you.

Thank you very much.

To be clear – this is not considered good style in Prolog, but it does show that you can write things in an “imperative” style if you really want to. (Under the covers, findall/3 and bagof/3 are implemented by something similar to this, although it’s not quite straightforward, as Richard O’Keefe’s book points out.)

In general, you can convert a set of facts into a list by this:

?- findall(X, mark(X), L).
L = [3, 18, 10].


?- bagof(X, mark(X), L).
L = [3, 18, 10].

and you can then easily iterate over the resulting list – or use sum_list/2 or aggregate(sum(X),mark(X),Sum) as others have pointed out.