我目前正在尝试学习一些基本的序言。在我学习的过程中,我想远离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).
我走向正确的轨道吗?
答案 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(由几个答案提出)这样一个有问题的结构?有几个原因:
在一般情况下,它打破了单调性。在纯粹的单调Prolog程序中,添加一个新事实将增加您可以从中获得的真实语句集。因此,在添加事实之前的所有事情都将是真实的。正是这个属性允许人们对程序进行非常有效的推理。但请注意,单调性意味着您无法对您可能想要建模的每种情况进行建模。想一个如果一个人没有孩子就应该成功的谓词childless/1
。我们假设childless(john).
是真的。现在,如果你添加一个关于john
作为某个孩子的父亲的新事实,它将不再认为childless(john)
是真的。因此,有些情况本身需要一些非单调结构。但是有许多情况可以在单调部分建模。坚持那些。
if-then-else容易导致难以阅读的嵌套。只要看看你的if-then-else程序,然后尝试回答“结果何时为-1”?答案是:“如果a > b
都不为真,a == b
为真”。很冗长,不是吗?因此,维护,修改和调试程序的人员必须“付钱”。
从您的示例中不清楚您正在考虑哪些参数,如果您对整数感到满意,请考虑使用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}之间的关系}和A
。 B
和A
之间有三个相关的关系(这里,因为我们正在处理一个简单的案例,这三个案例对于所讨论的关系类型是详尽的),我们可以简单地描述什么值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.