Prolog 在查询中使用冗余目标 (考虑)对纯< /强>程序1>代码> -g00../>代码>查询>代码> -g0,g0?有什么?

Prolog 在查询中使用冗余目标 (考虑)对纯< /强>程序1>代码> -g00../>代码>查询>代码> -g0,g0?有什么?,prolog,logical-purity,Prolog,Logical Purity,脚注 1无表格(为安全起见),约束条件正常。 关于这个问题。 考虑一个纯程序1?-G_0的查询。如果有的话,查询有什么用?-G_0,G_0。有吗 我认为第二个目标没有任何用处,特别是当尾部递归优化(上次调用优化)处于开启状态时 当查询是资源贪婪的,并且上面的选项是关闭的时(例如调试时),我可能会意识到GC问题(堆栈/堆溢出) 我认为第二个调用是冗余的(对于纯程序),应该由编译器消除。查询?-G\u 0,G\u 0。有助于识别?-G\u 0的冗余答案。 为此,只需将?-G_0.的答案数与?-G_

脚注
1无表格(为安全起见),约束条件正常。
关于这个问题。

考虑一个纯程序1?-G_0的查询。如果有的话,查询有什么用?-G_0,G_0。有吗

我认为第二个目标没有任何用处,特别是当尾部递归优化上次调用优化)处于开启状态时

当查询是资源贪婪的,并且上面的选项是关闭的时(例如调试时),我可能会意识到GC问题(堆栈/堆溢出)


我认为第二个调用是冗余的(对于纯程序),应该由编译器消除。

查询
?-G\u 0,G\u 0。
有助于识别
?-G\u 0的冗余答案。

为此,只需将
?-G_0.
的答案数与
?-G_0,G_0.
的答案数进行比较即可。无需存储这些答案(无论如何,这是一个常见的错误源)。只要两个整数就足够了!如果它们相等,那么就没有冗余。但是如果
?-G_0,G_0.
有更多的答案,那么就有一些冗余。以下是一个例子:

p(f(_,a)).
p(f(b,_)).

?- p(X).
   X = f(_A, a)
;  X = f(b, _A).  % two answers

?- p(X), p(X).
   X = f(_A, a) 
;  X = f(b, a)
;  X = f(b, a)
;  X = f(b, _A).   % four answers
                   % thus p(X) contains redundancies
。。。现在我们来解决这个问题:

p(f(B,a)) :-
   dif(B, b).
p(f(b,_)).

?- p(X).
   X = f(_A, a), dif(_A, b)
;  X = f(b, _A).

?- p(X), p(X).
   X = f(_A, a), dif(_A, b), dif(_A, b).
;  X = f(b, _A).    % again two answers, thus no redundancy
无需手动检查所涉及的约束

当我们仅使用搜索引擎显式搜索冗余答案时,这可以进一步扩展


长期以来,逻辑学家和数学家已经发现了一个一阶公式,用于检查一个关系是否具有唯一的结果。这用于定义关系何时为函数。这是一个非常简单的公式。对于某些
x
,关系
R(x,y)
具有唯一的
y
或无
y

∀y1∀y2(R(x, y1) & R(x, y2) => y1 = y2)
另请参见唯一性量化器
∃!被分为存在性和唯一性子句。我们如何才能将上述目标转化为一个目标?我们可以取它的否定式,得到这个公式:

∃y1∃y2(R(x, y1) & R(x, y2) & y1 ≠ y2)
当我们去掉存在量词
∃y1
∃y2
,一个序言将为我们提供
y1
y2
的答案替换。因此,这实际上不是模式
G_0,G_0
,而是带有一些额外的
G_0,G_0'。我们可以将其应用于@false示例:

p(f(_,a)).
p(f(b,_)).
通过第/3条的帮助,我们得到:

?- clause(p(X), _, Y1), clause(p(X), _, Y2), Y1 \== Y2.
X = f(b, a),
Y1 = <clause>(0x600000254280),
Y2 = <clause>(0x6000007d2840) ;
X = f(b, a),
Y1 = <clause>(0x6000007d2840),
Y2 = <clause>(0x600000254280) ;
false.
?-子句(p(X),X,Y1),子句(p(X),X,Y2),Y1\==Y2。
X=f(b,a),
Y1=(0x600000254280),
Y2=(0x6000007d2840);
X=f(b,a),
Y1=(0x6000007d2840),
Y2=(0x600000254280);
错。

因此,术语
f(b,a)
是两个子句的主要实例,这是唯一这样的术语。

将结果数平方?我认为在连续运行目标时不会保留任何状态信息。换句话说,问题的变化是不允许的,例如
?-g_0(State),g_0(State)。
从第一个目标的结果到第二个目标的堆栈上也没有传递任何状态?
g_0
可以是任何(纯)目标,包括
g_0=append(Xs,Ys,Zs)
@GuyCoder:需要连接。(使用
G_0;G_0
可以测试副作用或性能/缓存/标签问题)顺便说一句,不是
G_0(状态),而是G_0(状态)
一个人编写
call(G_1,状态),call(G_1,状态)
?- clause(p(X), _, Y1), clause(p(X), _, Y2), Y1 \== Y2.
X = f(b, a),
Y1 = <clause>(0x600000254280),
Y2 = <clause>(0x6000007d2840) ;
X = f(b, a),
Y1 = <clause>(0x6000007d2840),
Y2 = <clause>(0x600000254280) ;
false.