没有if和else语句的Prolog

时间:2014-03-05 04:50:09

标签: prolog logic

我目前正在尝试学习一些基本的序言。在我学习的过程中,我想远离if else语句来真正理解语言。我这样做有困难。我有一个简单的函数,如下所示:

if a > b then 1
else if
   a == b then c
else
    -1;;

这只是一个非常简单的逻辑,我想转换成prolog。

所以在这里我感到非常困惑。我想先检查一下> b如果是这样输出1.我只是这样做:

sample(A,B,C,O):-
   A > B, 1,
   A < B, -1,
   0.

这就是我想出的。 o作为输出,但我不明白如何使输出1。有什么想法可以帮助我更好地理解这一点吗?

在做了一些之后我想出了这个,但它似乎不正确:

Greaterthan(A,B,1.0).
Lessthan(A,B,-1.0).
Equal(A,B,C).

Sample(A,B,C,What):-
    Greaterthan(A,B,1.0),
    Lessthan(A,B,-1.0),
    Equal(A,B,C).

我走向正确的轨道吗?

4 个答案:

答案 0 :(得分:6)

如果您真的想尝试理解该语言,我建议您使用CapelliC's first suggestion

sample(A, B, _,  1) :- A > B.
sample(A, B, C,  C) :- A == B.
sample(A, B, _, -1) :- A < B.

我不同意CappeliC你应该使用if / then / else语法,因为这样(根据我的经验)很容易陷入翻译不同结构的陷阱,最终做到了Prolog中的程序编程,没有完全掌握语言本身。

答案 1 :(得分:6)

TL; DR:不要。

您正在尝试将您熟悉的构造从其他编程语言翻译为Prolog。假设学习Prolog意味着基本上将一个构造映射到Prolog之后。毕竟,如果所有构造都已映射,您将能够将任何程序编码为Prolog。

然而,通过这样做,你完全错过了Prolog的本质。

Prolog由纯粹的monotonic核心和一些程序装饰组成。如果你想了解Prolog与其他编程语言的区别,那么你应该首先研究它的核心。这意味着,你应该忽略那些其他部分。你只有那么多的注意力,如果你浪费时间去处理所有这些非单调的,甚至是程序性的结构,你很可能会错过它的本质。

那么,为什么一般的if-then-else(由几个答案提出)这样一个有问题的结构?有几个原因:

  1. 在一般情况下,它打破了单调性。在纯粹的单调Prolog程序中,添加一个新事实将增加您可以从中获得的真实语句集。因此,在添加事实之前的所有事情都将是真实的。正是这个属性允许人们对程序进行非常有效的推理。但请注意,单调性意味着您无法对您可能想要建模的每种情况进行建模。想一个如果一个人没有孩子就应该成功的谓词childless/1。我们假设childless(john).是真的。现在,如果你添加一个关于john作为某个孩子的父亲的新事实,它将不再认为childless(john)是真的。因此,有些情况本身需要一些非单调结构。但是有许多情况可以在单调部分建模。坚持那些。

  2. if-then-else容易导致难以阅读的嵌套。只要看看你的if-then-else程序,然后尝试回答“结果何时为-1”?答案是:“如果a > b都不为真,a == b为真”。很冗长,不是吗?因此,维护,修改和调试程序的人员必须“付钱”。

  3. 从您的示例中不清楚您正在考虑哪些参数,如果您对整数感到满意,请考虑使用library(clpfd),因为它在SICStus,SWI,YAP中可用:

    sample(A,B,_,1) :- A #> B.
    sample(A,B,C,C) :- A #= B.
    sample(A,B,_,-1) :- A #< B.
    

    这个定义现在很普遍,你甚至可以问

      

    何时会返回-1

    ?- sample(A,B,C,-1).
      A = B,
      C = -1,
      B in inf..sup
    ;
      A#=<B+ -1.
    

    所以有两种可能性。

答案 2 :(得分:4)

以下是CapelliC有用答案的一些附录:

在开始时,有时容易错误地设想Prolog谓词的功能。它们要么根本不是函数,要么它们是n-ary函数,它们只会产生真或假的输出。但是,我经常发现忘记函数并且只是关联地考虑谓词是有帮助的。当我们定义谓词p/n时,我们将描述n元素之间的关系,并且我们将关系命名为p

在你的情况下,听起来就像我们在有序三元组<A, B, C>上定义条件一样,其中C的值取决于{{1}之间的关系}和ABA之间有三个相关的关系(这里,因为我们正在处理一个简单的案例,这三个案例对于所讨论的关系类型是详尽的),我们可以简单地描述什么值C应该有这三种情况。

B

请注意,我使用了算术运算符sample(A, B, 1.0) :- A > B. sample(A, B, -1.0) :- A < B. sample(A, B, some_value) :- A =:= B. 。这比=:=/2更具体,它让我们可以比较数学表达式的数值相等性。 ==/2检查术语的等效性==/2都是正确的,因为等效术语位于运算符的左侧和右侧。但是a == a, 2 == 2, 5+7 == 5+7都是假的,因为它是被比较的术语本身,在第一种情况下,值是相反的,在第二种情况下,我们将5+7 == 7+5, 5+7 == 12, A == a与整数进行比较,在第三种情况下我们将自由变量与原子进行比较。但是,以下情况属实:+(5,7)。这将让我们用可评估的数学表达式统一A和B,而不仅仅是整数或浮点数。然后我们可以提出诸如

之类的查询
2 =:= 2, 5 + 7 =:= 12, 2 + 2 =:= 4 + 0

CapelliC指出,当我们为谓词编写多个子句时,我们正在表达析取。他还小心地注意到,这个特定的例子只是因为替代性本质上是相互排斥的,所以它只是一种简单的分离。他展示了如何通过干预解决方案来解决你的第一个“if ... then ... else if else else else”的结构所带来的相同排他性。实际上,如果您查阅条件->/2的swi-prolog文档,您会看到?- sample(2^3, 2+2+2, X). X = 1.0 ?- sample(2*3, 2+2+2, X). X = some_value. 的语义解释为cut,->/2和disjunctions,!

我在CapelliC和SQB之间中途处理了控制谓词的使用。我认为你坚持用单独的子句定义这些东西是明智的,同时你还在学习语法的基础知识。但是,;只是另一个带有一些语法糖的谓词,所以你不应该害怕它。一旦你开始考虑关系而不是功能或命令,你可能会发现->/2是一个非常好的工具,可以简洁地表达关系模式。我会使用控制谓词来格式化我的子句:

->/2

答案 3 :(得分:2)

您的代码既有句法问题也有语义问题。

谓词开始小写,逗号表示连词。也就是说,您可以将您的条款视为

sample(A,B,C,What) if
    greaterthan(A,B,1.0) and lessthan(A,B,-1.0) and equal(A,B,C).

然后注意What参数是无用的,因为它没有得到值 - 它被称为单例。

写一种分离的可能方式(即OR)

sample(A,B,_,1) :- A > B.
sample(A,B,C,C) :- A == B.
sample(A,B,_,-1) :- A < B.

请注意测试A < B以保护值-1的分配。这是必要的,因为如果需要,Prolog将执行所有子句。强制Prolog避免一些我们知道的计算的基本构造应该这样做cut

sample(A,B,_,1) :- A > B, !.
sample(A,B,C,C) :- A == B, !.
sample(A,B,_,-1).

无论如何,我认为你应该使用if / then / else语法,即使在学习的时候也是如此。

sample(A,B,C,W) :- A > B -> W = 1 ; A == B -> W = C ; W = -1.