Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 带有if-else和multiple子句谓词的单子句_Performance_Prolog - Fatal编程技术网

Performance 带有if-else和multiple子句谓词的单子句

Performance 带有if-else和multiple子句谓词的单子句,performance,prolog,Performance,Prolog,假设我想要实现一个谓词,该谓词“返回”一个列表所共享的所有元素的列表 我可以将其实现为一个子句(对于逻辑编程来说,看起来有点难看): 或作为一组条款: shared_members([], []). % possibly adding cut here to increase effciency shared_members(Members, Lists) :- findall(M, (maplist(member(M), Lists)), Members). 哪种实施被认为更有效?

假设我想要实现一个谓词,该谓词“返回”一个列表所共享的所有元素的列表

我可以将其实现为一个子句(对于逻辑编程来说,看起来有点难看):

或作为一组条款:

shared_members([], []). % possibly adding cut here to increase effciency

shared_members(Members, Lists) :-
    findall(M, (maplist(member(M), Lists)), Members).
哪种实施被认为更有效?
我知道这取决于Prolog的实现,但可能对这些情况的效率有一个普遍的看法。

在这种情况下,您甚至不需要第一个子句
shared\u成员([],[])
findall/3
调用将导致
Members=[]
如果
Lists=[]

不过,这个问题仍然很有趣,所以我们暂时忽略这个问题。您可以运行一些统计数据来确定时间效率。内存效率差异可以忽略不计。然而,给出的第二种方法被认为是Prolog中的规范方法。但他们的行为也不相同。Prolog中的“if-else”,由
p1->p2表示;p3
cuts在对p1求值后删除选择点。它相当于
p1!,p2;p3

这就是为什么这很重要。我将使用一个人为的例子(它也不需要两个子句,但说明了这一点)。我将定义一个
len/2
谓词,如果第一个参数是第二个参数的长度,则该谓词为true:

len(0, []).
len(N, L) :- length(L, N).
显然,与原始问题的情况一样,这里的第一条是多余的,但它对于这个说明很重要。如果运行此查询,将得到以下结果:

| ?- len(N, [a,b,c]).

N = 3

yes
| ?- len(3, L).

L = [_,_,_]

yes
| ?- len(N, L).

L = []
N = 0 ? ;

L = []
N = 0 ? ;

L = [_]
N = 1 ? ;

L = [_,_]
N = 2 ? ;

L = [_,_,_]
N = 3 ?
请注意,如果两个参数都是变量,它将枚举解决方案。(另外,由于第1条多余,其中一个解决方案出现了两次。)

让我们用“if-else”重写这个谓词:

我们将运行它:

| ?- len(N, [a,b,c]).

N = 3

yes
到目前为止,一切顺利。但是

| ?- len(3, L).

no
| ?- len(N, L).

L = []
N = 0

yes
| ?-
哎呀!这是完全不同的。发生了什么事

在第二种方法中,
(L=[]->N=0;length(L,N))
首先尝试统一
L
[]
。如果
L
是一个变量,则此操作将成功执行
L=[]
。由于成功,Prolog随后尝试统一
N=0
。但是使用查询
len(3,L)
N
已经绑定到3。因此
N=0
失败,整个子句也失败


使用
->构造大大降低了实现的通用性,并在某些调用场景中产生错误的结果。

在这种情况下,您甚至不需要第一个子句
共享_成员([],[])
findall/3
调用将导致
Members=[]
如果
Lists=[]
。如果您真正关心性能,请摆脱findall和member!
| ?- len(N, [a,b,c]).

N = 3

yes
| ?- len(3, L).

no
| ?- len(N, L).

L = []
N = 0

yes
| ?-