This is not true: 1 is an element of identification of "numbers" during multiplication. You can, for example, distract the operation and the loop to have something line by line:
list_op_product(L, Op, P) :- identity_element(Op, IE), reverse(L, R), % no foldr in SWI-Prolog, at least foldl(Op, R, IE, P).
Therefore, you need to define identity_element/2 and the operation itself. Thus, adding and multiplying will look something like this:
identity_element(add, 0). identity_element(mult, 1). add(X, Y, R) :- R is X + Y. mult(X, Y, R) :- R is X * Y.
And then you can say:
?- list_op_product([2,3,4], add, Sum). Sum = 9. ?- list_op_product([2,3,4], mult, Product). Product = 24.
Similarly, the string concatenation identification element is an empty string. So, if you just added the following sentence to identity_element/2 :
identity_element(atom_concat, '').
Now you can say:
?- list_op_product([a,b,c], atom_concat, R). R = abc.
Of course, most of this is not needed, but it shows the point.
As for the other answer : perhaps a cleaner way than a cut to avoid incorrect answers:
product([], 0). product([H|T], P) :- product_1(T, H, P). product_1([], P, P). product_1([H|T], H0, P) :- product_1(T, H, P0), P is P0 * H0.
So now:
?- product([2,3,5], P). P = 30. ?- product([], P). P = 0.
But that seems wrong. You should have a base case:
product([], 1).
This product/2 section simply defines what your identity element is; thatโs why itโs better to leave 1 there and not replace it with 0! However, you will do one multiplication less for non-empty lists (you will not have the last * 1 ). This is an effective and easy to use optimization. If you try to find a product of a type that does not have an identification element at all, then product([], X) not defined. You can either leave this sentence and then ?- product([], X) fail. Or maybe you can make a mistake?