,
您对as binary function的性质是正确的,但翻译为and
尚未解释如何解释连词。让我们看一下一般的 Prolog 规则:
head :- % we disregard variables at the moment
goal1,
goal2,
goal3.
fact. % a fact is a rule without a body
这可以理解为“目标暗示着头脑”,或者“推导出我们需要推导出每个目标的头脑”。但是goal1 本身可能是一个规则,所以我们需要某种TODO 列表(通常实现为堆栈,但现在确切的行为并不重要)。我们从 TODO 列表上的查询开始。如果列表中的某个元素是事实,我们可以将其删除。要删除规则,我们需要导出所有目标,因此我们将列表中的头部替换为目标。让我们看一个例子:
make(coffee).
make(tea).
make(orange_juice).
make(croissant).
make(scrambled_eggs).
prepare(beverage) :-
make(coffee).
prepare(beverage) :-
make(tea).
prepare(beverage) :-
make(orange_juice).
prepare(food) :-
make(croissant).
prepare(food) :-
make(scrambled_eggs).
breakfast :-
prepare(beverage),
prepare(food).
当我们查询早餐时,我们得到:
?- breakfast.
true ;
true ;
true ;
true ;
true ;
true.
不知道我们早餐吃什么有点无聊,但是有六种方法可以吃到一种。那么我们是如何到达那里的呢?
我们从待办事项清单上的早餐开始:
唯一适合的规则头是最后一个,所以我们将 TODO 更改为:
我们现在有多个规则告诉我们要制作什么饮料,让我们选择第一个:
幸运的是,make(coffee)
这是事实,因此我们可以将其从列表中划掉。
同样,我们可以准备食物:
并且因为有一个相应的事实,我们已经完成了早餐(输出true
)。但我们做了一些选择:我们可以准备茶或橙汁来代替咖啡,我们可以用炒鸡蛋代替羊角面包。这意味着我们可以回溯:
好的,那里没有选择,让我们更进一步:
并将其扩展为
这又是一个事实(true
再次:))。当我们进一步回溯时,我们得到了制作饮料和食物的所有组合,并true
为所有 6 种组合打印。
切口可防止回溯到放置之前的某个点。让我们修改规则如下:
breakfast :-
prepare(beverage),
!,
prepare(food).
现在我们无法撤销饮料选择,所以我们最终会得到咖啡和炒鸡蛋或咖啡和羊角面包:
?- breakfast.
true ;
true.
所以合取告诉我们接下来要推导出哪些东西,而切分告诉我们停止回溯。在这两种情况下,我们都需要一个数据结构来记录我们已经做出的最后一系列选择。它必须是一个序列,因为我们需要记住我们还可以选择什么作为饮料和食物。在切割的情况下,我们可以忘记最后一个切割之后的序列中的所有内容,即切割切断选择点序列。因此,我们致力于那个特定的选择。
我希望这对实施有所帮助。