Prolog 从序言艺术看练习的左撇子

Prolog 从序言艺术看练习的左撇子,prolog,Prolog,在这本书中,我们被要求使用以下布局来定义left_of、right_of、over和down谓词 % bike camera % pencil hourglass butterfly fish left_of(pencil, hourglass). left_of(hourglass, butterfly). left_of(butterfly, fish). above(bike, pencil). above(camera, butterfly). r

在这本书中,我们被要求使用以下布局来定义left_of、right_of、over和down谓词

% bike               camera
% pencil  hourglass  butterfly  fish

left_of(pencil, hourglass).
left_of(hourglass, butterfly).
left_of(butterfly, fish).

above(bike, pencil).
above(camera, butterfly).

right_of(Obj1, Obj2) :-
    left_of(Obj2, Obj1).

below(Obj1, Obj2) :-
    above(Obj2, Obj1).
这似乎找到了正确的解决办法

在本书的后面部分,我们被要求为左函数添加一个递归规则。我能找到的唯一解决办法是使用不同的函子名称:left_of 2。所以我基本上重新实现了祖先关系

left_of2(Obj1, Obj2) :-
    left_of(Obj1, Obj2).
left_of2(Obj1, Obj2) :-
    left_of(Obj1, X),
    left_of2(X, Obj2).

在我尝试重用left_的过程中,我可以得到所有正确的解决方案,但在最后一次重做时,出现了堆栈溢出。我猜这是因为我没有定义正确的基本情况。这是否可以使用left_of for facts和递归过程进行编码?

正如注释中所提到的,不幸的是,在Prolog中,必须使用单独命名的谓词才能进行编码。如果你不这样做,你会得到这样的结果:

left_of(X,Z) :- left_of(X,Y), left_of(Y,Z).
这会给你两次无界递归。事实和谓词共享同一个名称原则上没有错——事实上,基本案例规则看起来像事实是很常见的。只是处理这样的可传递闭包情况会导致堆栈溢出,除非这两个步骤中有一个是有限的,并且在Prolog中,除了分别命名它们之外,没有其他方法可以确保这一点

在Prolog中,这远远不是唯一一种被迫将工作分解为单独谓词的情况。其他常见的情况包括带有初始值设定项或终结器的计算循环

按照惯例,谓词的命名与事实不同。例如,
直接\u左\u of
表示事实,
左\u of
表示谓词。使用模块系统或Logtalk,您可以轻松隐藏“直接”版本,并鼓励用户使用可传递版本。您还可以为隐藏的名称使用一个令人不舒服的名称,例如
left\u of_uu
,使意图更加明确,而不被禁止


在其他语言中,函数是一种更不透明、更大的抽象,并且有一些工具可以隐藏大量的工作。相比之下,Prolog的谓词“更简单”,这曾经让我感到困扰。现在我很高兴它们变得更简单了,因为有足够多的其他东西在进行,我很高兴我不必再找出变量的算术谓词或关键字参数(尽管如果需要的话,你可以很容易地用列表模拟两者)。

真的吗?对我来说,它似乎工作正常。Daniel,我的问题是可以将left_of用于事实和递归规则(而不必使用left_of 2)。我可能是把这本书的练习理解错了。在这种情况下,答案是否定的。在Prolog中,有很多情况下,您必须有单独的谓词,而在其他语言中不需要它们(还想到了带有初始化或终结步骤的循环)。这只是其中之一。您总是可以用不同的名称隐藏“内部”谓词(
直接\u left\u of/2
),并将
left\u of/2
作为
left\u of
公开给您的用户。@DanielLyons:如果您作为答案发布,我会投赞成票。在序言中这样做是正确的。@larsmans谢谢,就这样做了。谢谢Daniel的解释。Prolog是迄今为止我尝试过的最具挑战性的语言。(方案,CL,Cljule,Python,C++,C)一开始它非常不可思议,它变得更好,更有趣,但是保持怪异。我很高兴你能试一试,你正在读一本经典的书,这本书对你有很大的帮助,你的FP背景也是如此。我很高兴能帮上忙,请随时给我发电子邮件。