这是Ivan Bratko的书“Prolog Programming for Artificial Intelligence - 3rd edition - pg 377”中的代码示例。它适用于查询?-value(kiwi, active_at, night)
。将结果显示为true
。
但它也会为查询true
提供?- value(kiwi, active_at, daylight).
的结果,它应该是false
。
我应该如何修改它,或者我错过了什么?
%--------Define frames
bird(a_kind_of, animal).
bird(active_at, daylight).
albatross(a_kind_of, bird).
albatross(colour, black).
albatross(size, 10).
kiwi(a_kind_of, bird).
kiwi(active_at, night).
kiwi(colour, brown).
kiwi(size, 24).
albert(instance_of, albatross).
albert(size, 10).
%--------Inference in Frames
value(Frame, Slot, Value):-
Query =.. [Frame, Slot, Value],
call(Query), !. %Value is directly retrieved
value(Frame, Slot, Value):-
parent(Frame, ParentName),
value(ParentName, Slot, Value). % More general rule
parent(Frame, ParentName):-
(Query =.. [Frame, a_kind_of, ParentName];
Query =.. [Frame, instance_of, ParentName]),
call(Query).
答案 0 :(得分:2)
首先让我们来看看有问题的查询。你的第一个问题......
?- value(kiwi, active_at, night).
true.
...使用第一个值/ 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.
......也取得了成功。值/ 3的第一个规则将Query
与kiwi(active_at, daylight)
统一起来,然后调用它:
?- call(kiwi(active_at, daylight)).
false.
此调用失败,因为您没有合适的事实。请注意,此时规则无法成功,因此Prolog不会为最后一个目标而烦恼,并继续执行第二个值/ 3规则。这是第一个目标
?- parent(kiwi,ParentName).
ParentName = bird ;
false.
...由于分离的第一个参数,成功并将ParentName
与bird
统一起来......
?- Query =.. [kiwi, a_kind_of, ParentName].
Query = kiwi(a_kind_of, ParentName).
...以及父母/ 2中的后续调用/ 1:
?- call(kiwi(a_kind_of, ParentName)).
ParentName = bird.
现在,第二个值/ 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的削减而确定性地成功,但是调用谓词的第一个目标(parent(kiwi,ParentName)
)(第二个值/ 3的规则)仍然存在一个选择点打开(参见上面的查询),现在Prolog正在回溯那里搜索其他解决方案。但是Prolog没有答案:
?- value(kiwi, active_at, daylight).
true ;
false.
但是,如果你问猕猴桃什么时候活跃,Prolog会回答:
?- value(kiwi, active_at, X).
X = night.
此处未导出daylight
的原因再次被削减。在{/ 1}}的第一个值/ 3成功后,它会阻止Prolog搜索其他解决方案。从逻辑的角度来看,这种行为是完全错误的:要么猕猴桃在白天和晚上都是活跃的,那么最后一个查询应该产生两个解决方案,或者它们是夜间活动,那么查询X = night
应该失败。我不想推测谓词值/ 3的预期行为,所以我将引用Wikipedia entry on kiwi来代替哪些状态: Kiwi很害羞而且通常是夜间的。他们大多是夜间活动的习惯可能是捕食者(包括人类)栖息地入侵的结果。在新西兰引进捕食者的地区,例如庇护所,猕猴桃经常在白天被看到。
如果你想要两种解决方案,我建议添加一些事实iscallable / 1(不要称之为可调用/ 1,因为那里已经内置了该名称)你的事实,将它添加到value / 3和parent / 2并删除剪切,如下所示:
?- value(kiwi, active_at, daylight).
通过这些改动,您将始终获得两种解决方案:
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).
要查看为什么在值/ 3的规则1中需要类似iscallable / 1的内容,请将其删除并考虑以下查询:
?- value(kiwi, active_at,X).
X = night ;
X = daylight ;
false.
?- value(kiwi, active_at,night).
true ;
false.
?- value(kiwi, active_at,daylight).
true ;
false.
谓词值/ 3试图调用不存在的谓词动物/ 2。要查看为什么需要父/ 2中的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
另一方面,如果你只选择夜间解决方案,你可以定义一个事实nocturnalbird / 2来描述夜间活动并相应地改变事实kiwi / 2:
?- 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(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.
以及在值/ 3和父/ 2中包含iscallable / 1像上面一样。
事实上,你根本不需要= .. / 2,正如评论中@false所指出的那样。你可以简单地使用call / N:
nocturnalbird(a_kind_of, animal).
答案 1 :(得分:1)
我很晚才遇到这个问题,但另一种处理方法是将 value 的第一个子句更改为:
value(Frame, Slot, Value):-
call(Frame, Slot, V), !, % Value is directly retrieved
V = Value. % Slot might already inherit value so check