使用Prolog在框架中实现推理的代码问题

时间:2017-11-24 07:58:39

标签: prolog

这是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).

2 个答案:

答案 0 :(得分:2)

首先让我们来看看有问题的查询。你的第一个问题......

?- value(kiwi, active_at, night).
true.

...使用第一个值/ 3成功。如果您手动尝试目标,则可以看到。查询...

?- Query =.. [kiwi, active_at, night].

...成功并将变量Querykiwi(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的第一个规则将Querykiwi(active_at, daylight)统一起来,然后调用它:

?- call(kiwi(active_at, daylight)).
false.

此调用失败,因为您没有合适的事实。请注意,此时规则无法成功,因此Prolog不会为最后一个目标而烦恼,并继续执行第二个值/ 3规则。这是第一个目标

?- parent(kiwi,ParentName).
ParentName = bird ;
false.

...由于分离的第一个参数,成功并将ParentNamebird统一起来......

?- 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