这并没有错:1 是乘法下“数字”的identity element。例如,您可以抽象出操作和循环,以获得以下内容:
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).
所以你只需要定义identity_element/2 和操作本身。因此,加法和乘法将类似于:
identity_element(add, 0).
identity_element(mult, 1).
add(X, Y, R) :- R is X + Y.
mult(X, Y, R) :- R is X * Y.
然后你可以说:
?- list_op_product([2,3,4], add, Sum).
Sum = 9.
?- list_op_product([2,3,4], mult, Product).
Product = 24.
同样,字符串连接的标识元素是空字符串。所以,如果你只是将以下子句添加到identity_element/2:
identity_element(atom_concat, '').
你现在可以说:
?- list_op_product([a,b,c], atom_concat, R).
R = abc.
当然,这大部分是不必要的,但它说明了重点。
至于other answer:为了避免错误答案,可能有比剪切更清洁的方法:
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.
那么现在:
?- product([2,3,5], P).
P = 30.
?- product([], P).
P = 0.
但这感觉不对。您仍然应该有一个基本案例:
product([], 1).
product/2 的这个子句简单地定义了你的身份元素是什么;这就是为什么最好将 1 留在那里而不用 0 替换它!但是,对于非空列表,您将少做一次乘法(您不会有最后一个 * 1)。这是一个有效且易于进行的优化。如果您尝试查找根本没有标识元素的类型的乘积:那么,product([], X) 未定义。您可以省略该子句,然后 ?- product([], X) 将失败。或者,您可能会抛出错误?