析取G1; G2 vs.If-then-else Cond-> G1; G2

时间:2019-06-06 20:57:00

标签: if-statement syntax prolog iso-prolog

我遇到了一个Prolog程序,其中包含嵌套的if-then-else形式

p(X,Y) :-
     (cond1(X,Y) -> q(X)); true,
     (cond2(X,Y) -> q(Y)); true.

有意外的答案。此行为的原因与以下查询相同:

?- (true, (true -> X=a)); X=b.
X = a ;
X = b.

?- ((true -> X=a), true); X=b.
X = a ;
X = b.

?- (true -> X=a); X=b.
X = a.

第一个查询有两个答案,但是第二个只有一个。行为不同的原因是什么?

P.S .:我知道其中的区别,但是我还没有找到解决这种相当混乱现象的SO问题。那么为什么不这样记录呢?

2 个答案:

答案 0 :(得分:2)

关于析取的可追踪性。 这两个查询在结构上不同:

trace, (true -> X=a); X=b.

trace, ((true -> X=a); X=b).

您可以使用write_canonical / 1查看区别:

?- write_canonical((trace, (true -> X=a); X=b)), nl.
;(','(trace,->(true,=(A,a))),=(A,b))
true.

?- write_canonical((trace, ((true -> X=a); X=b))), nl.
','(trace,;(->(true,=(A,a)),=(A,b)))
true.

它们的行为也有所不同:

?- trace, (true -> X=a); X=b.
   Call: (9) true ? creep
   Exit: (9) true ? creep
   Call: (9) _428=a ? creep
   Exit: (9) a=a ? creep
X = a 
   Call: (9) _428=b ? creep
   Exit: (9) b=b ? creep
X = b.

[trace]  ?- trace, ((true -> X=a); X=b).
   Call: (9) true ? creep
   Exit: (9) true ? creep
   Call: (9) _706=a ? creep
   Exit: (9) a=a ? creep
X = a.

只有第二个查询会测试(true-> X = a); X = b。

答案 1 :(得分:0)

首先让我们解决初始谓词:格式建议嵌套if-then-else,但是第二个主体周围的括号将第一个true分组到else分支:

?- listing(p).
p(A, B) :-
    (   cond1(A, B)
    ->  q(A)
    ;   true,
        (   cond2(A, B)
        ->  q(B)
        )
    ;   true
    ).

这就是我们以true, ...开头的查询结束的方式。这里的第二个问题是;的使用是重载的:仅当G1; G2的形式不是G1时,(Cond -> Goal)形式的术语才被解释为析取。否则,将其解释为if-then-else。让我们看一下不同的情况:

  • (true, true -> X=a); X=b;解释为析取,因为左侧最外面的函子是连词,。 Prolog报告每个分支的答案替换。
  • (true -> X=a, true); X=b:出于相同原因是析取
  • (true -> X=a); X=b:是if-then-else,因为左侧最外面的函子是if-then运算符->。 Prolog仅报告true分支的答案替代。

有趣的是,当我们将条件放入变量中时,这似乎不再起作用(在SWI 8上):

?- G1 = (true -> (X = a)), (G1 ; X=b).
G1 =  (true->a=a),
X = a ;
G1 =  (true->b=a),
X = b.

当我将G1包装到call/1中时,也会发生同样的事情:

?- G1 = (true -> (X = a)), (call(G1) ; X=b).
G1 =  (true->a=a),
X = a ;
G1 =  (true->b=a),
X = b.

如果我正确阅读了先前问题的answer,则第一个问题应该与众不同。

我认为,不同的跟踪行为是断点会干扰if-then-else的检测。在跟踪过程中,我的错误是击中enter来爬行,但没有意识到当报告实际答案时,我需要输入;