Prolog - 查找列表的产品

a1y*_*1yx 6 list prolog

我是prolog(swi prolog)的新手,很抱歉,如果这是一个愚蠢的问题.这也是一项单一的任务.我被要求找到列表的产品,这就是我想出的:

product([],1).
product([H|T], Product) :-
    product( T, Product1),
    Product is H * Product1.
Run Code Online (Sandbox Code Playgroud)

最长的我有基本情况:

product([],0).
Run Code Online (Sandbox Code Playgroud)

但这使一切都变为零.但是,在测试基本情况时 product([],Product),我得到一个 - 这是不正确的.任何解决方案的提示将不胜感激.

小智 6

这不是不正确的:1是乘法下"数字" 的标识元素.例如,您可以抽象出操作和循环,以获得以下内容:

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).
Run Code Online (Sandbox Code Playgroud)

所以你只需要定义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.
Run Code Online (Sandbox Code Playgroud)

然后你可以说:

?- list_op_product([2,3,4], add, Sum).
Sum = 9.

?- list_op_product([2,3,4], mult, Product).
Product = 24.
Run Code Online (Sandbox Code Playgroud)

类似地,字符串连接的标识元素是空字符串.因此,如果您只是将以下子句添加到identity_element/2:

identity_element(atom_concat, '').
Run Code Online (Sandbox Code Playgroud)

你现在可以说:

?- list_op_product([a,b,c], atom_concat, R).
R = abc.
Run Code Online (Sandbox Code Playgroud)

当然,大部分内容都是不必要的,但它说明了这一点.

至于另一个答案:为了避免错误的答案,可能有一种比剪辑更简洁的方法:

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.
Run Code Online (Sandbox Code Playgroud)

所以现在:

?- product([2,3,5], P).
P = 30.

?- product([], P).
P = 0.
Run Code Online (Sandbox Code Playgroud)

但这感觉不对.你应该还有一个基本案例:

product([], 1).
Run Code Online (Sandbox Code Playgroud)

这个条款product/2简单地定义了你的身份元素; 这就是为什么将1留在那里并且不用0替换它仍然更好!但是,对于非空列表,您将执行一次乘法运算(您不会使用最后一个* 1).这是一个有效且易于制作的优化.如果您尝试查找根本没有标识元素的类型的产品:那么,product([], X)未定义.您可以省略该条款,然后?- product([], X)将失败.或者,您可以抛出错误?

  • @Boris,我知道,这就是为什么我没有陈述:"名称`list_op_product/3`根本不适合*." ;-)它在"sum"的情况下不太适合. (2认同)
  • @mat好的,你说的一切都很有道理.在我无休止(也可能被误导)的知识追求中,我一直在努力阅读由Alex Stepanov(C++ STL成名)共同撰写的一本书.他处理这些问题(使用C++)的方式实际上是定义算法,这些算法取决于为传递给它们的特定类型定义的操作.例如,你不能将半群的元素提升到0的幂等等(具体例子见`power_semigroup(a,n,op)`[在这里定义](http://www.fm2gp.com/code /ch07.h). (2认同)