首先让我们看看有问题的查询。您的第一个查询...
?- value(kiwi, active_at, night).
true.
... 以 value/3 的第一条规则成功。如果您手动尝试目标,您会看到这一点。查询...
?- Query =.. [kiwi, active_at, night].
...成功将变量Query与kiwi(active_at, night)统一起来:
?- Query =.. [kiwi, active_at, night].
Query = kiwi(active_at, night).
下一个目标调用Query...
?- call(kiwi(active_at, night)).
true.
...并且成功了,因为您有一个事实kiwi(active_at, night).。下一个目标! 阻止 Prolog 回溯和搜索进一步的解决方案,因此查询 ?- value(kiwi, active_at, night). 确定性地成功(您不必在第一个解决方案之后按 ;)。现在让我们看看您的第二个查询...
?- value(kiwi, active_at, daylight).
true ;
false.
...也成功了。 value/3 的第一条规则将Query 与kiwi(active_at, daylight) 统一起来,随后调用它:
?- call(kiwi(active_at, daylight)).
false.
此调用失败,因为您没有合适的事实。请注意,此时该规则无法成功,因此 Prolog 不会理会最后一个目标并继续执行 value/3 的第二个规则。这是第一个目标
?- parent(kiwi,ParentName).
ParentName = bird ;
false.
...由于析取的第一个参数...成功并正在将ParentName 与bird 统一...
?- Query =.. [kiwi, a_kind_of, ParentName].
Query = kiwi(a_kind_of, ParentName).
... 以及 parent/2 中的后续调用/1:
?- call(kiwi(a_kind_of, ParentName)).
ParentName = bird.
现在 value/3 的第二个规则的第二个目标调用自己,再次从第一个规则开始:
?- value(bird, active_at, daylight).
true.
这成功了,因此查询...
?- value(kiwi, active_at, daylight).
true
... 也成功了。请注意,Prolog 在回答 true 后正在等待输入,如果您按 ;,它正在寻找进一步的解决方案:
?- value(kiwi, active_at, daylight).
true ;
虽然目标value(bird, active_at, daylight)由于第一个规则值/3的剪切而确定性地成功,但调用谓词(值/3的第二个规则)的第一个目标(parent(kiwi,ParentName))留下了一个选择点(请参阅上面的查询),现在 Prolog 正在回溯那里以寻找其他解决方案。但是没有这样 Prolog 的答案:
?- value(kiwi, active_at, daylight).
true ;
false.
但是,如果你问猕猴桃什么时候活跃,Prolog 会回答:
?- value(kiwi, active_at, X).
X = night.
daylight 之所以没有派生到这里,也是因为切入。在X = night 的第一条 value/3 规则成功后,它会阻止 Prolog 搜索其他解决方案。从逻辑的角度来看,这种行为是完全不正确的:要么猕猴桃在白天和晚上都活跃,那么最后一个查询应该产生两种解决方案,或者它们是夜间的,那么查询 ?- value(kiwi, active_at, daylight). 应该会失败。我不想推测谓词 value/3 的预期行为,所以我将参考 Wikipedia entry on kiwi 而不是它指出:猕猴桃很害羞,通常是夜间活动。它们主要是夜间活动的习惯可能是包括人类在内的捕食者入侵栖息地的结果。在新西兰一些引进的捕食者已经被移除的地区,例如保护区,猕猴桃经常在白天出现。
如果您想同时拥有这两种解决方案,我建议您添加一些涵盖您的事实的事实 iscallable/1(不要称它为 callable/1,因为已经有一个具有该名称的内置函数),将其添加到value/3 和 parent/2 并像这样删除剪切:
iscallable(bird). % <- new fact
iscallable(albatross). % <- new fact
iscallable(kiwi). % <- new fact
iscallable(albert). % <- new fact
value(Frame, Slot, Value):-
iscallable(Frame), % <- new goal iscallable/1
Query =.. [Frame, Slot, Value],
call(Query). % <- removed cut here
value(Frame, Slot, Value):-
parent(Frame, ParentName),
value(ParentName, Slot, Value).
parent(Frame, ParentName):-
iscallable(Frame), % <- new goal iscallable/1
(Query =.. [Frame, a_kind_of, ParentName];
Query =.. [Frame, instance_of, ParentName]),
call(Query).
通过这些更改,您将始终获得两种解决方案:
?- value(kiwi, active_at,X).
X = night ;
X = daylight ;
false.
?- value(kiwi, active_at,night).
true ;
false.
?- value(kiwi, active_at,daylight).
true ;
false.
要了解为什么在 value/3 的规则 1 中需要 iscallable/1 之类的东西,请将其删除并考虑以下查询:
?- value(kiwi, active_at, X).
X = night ;
X = daylight ;
ERROR: value/3: Undefined procedure: animal/2
Exception: (9) animal(active_at, _G4462) ? creep
Exception: (8) value(animal, active_at, _G4462) ? creep
谓词值/3 试图调用一个不存在的谓词animal/2。要了解为什么在 parent/2 中需要 iscallable/1 之类的内容,请将其删除并考虑以下查询:
?- value(kiwi, active_at,X).
X = night ;
X = daylight ;
ERROR: parent/2: Undefined procedure: animal/2
Exception: (10) animal(a_kind_of, _G4558) ? creep
另一方面,如果您只选择夜间解决方案,您可以定义描述夜间活动的事实 nocturnalbird/2 并相应地更改事实 kiwi/2:
nocturnalbird(active_at, night). % <- new fact
%kiwi(a_kind_of, bird). % <- remove fact
kiwi(a_kind_of, nocturnalbird). % <- new fact
%kiwi(active_at, night). % <- remove fact
kiwi(colour, brown).
kiwi(size, 24).
这会产生预期的结果:
?- value(kiwi, active_at,X).
X = night ;
false.
?- value(kiwi, active_at,night).
true ;
false.
?- value(kiwi, active_at,daylight).
false.
如果您打算扩展此示例以包括夜行性鸟类的动物属性,则需要添加一个事实 nocturnalbird(a_kind_of, animal). 以及在 value/3 和 parent/2 中包含 iscallable/1,如上所示。
编辑:
事实上,这里根本不需要 =../2,正如 cmets 中的 @false 所指出的那样。您可以简单地使用 call/N 代替:
value(Frame, Slot, Value):-
iscallable(Frame),
call(Frame, Slot, Value). % <- here
value(Frame, Slot, Value):-
parent(Frame, ParentName),
value(ParentName, Slot, Value).
parent(Frame, ParentName):-
iscallable(Frame),
(call(Frame, a_kind_of, ParentName); % <- here
call(Frame, instance_of, ParentName)). % <- here