我正在上课程编程范例。目前我们正在学习Prolog,而且我陷入了不同的范式。我试图从命令转换的功能之一是一个相对简单的功能。
foo(A,B,C)
if(A > B) C is 1
if(A < B) C is -1
if(A = B) C is 0
我很容易在Prolog中做到这一点。
foo(A,B,C) :- sub(A-B,C).
sub(E, C) :- E = 0, C is 0.
sub(E, C) :- E > 0, C is 1.
sub(E, C) :- E < 0, C is -1.
问题是,我只能在整个谓词中使用一个“is”(不能定义一个调用Is的较小谓词,而是调用那个或者任何东西),而且我不能使用Prolog的if / else结构。我无法弄清楚如何以声明的方式思考这个问题。
我想也许我可以做一些像C是(A-B)/ abs(A-B)的东西,但是在A = B上打破,并且需要2“是”语句。我只是卡住了。
答案 0 :(得分:1)
为了以声明方式编程,我们必须考虑我们要声明的内容,然后我们可以对其进行描述。为此,我将尝试编写谓词,以便它表示为什么C
的值在三种可能状态之间交替,这取决于A
和B
的相对大小。这是一个与您使用foo
描述的格式相同的谓词:
comparison(A, B, less) :- A < B.
comparison(A, B, equal) :- A =:= B. %% =:=/2 is "True if expression A evaluates to a number equal to B".
comparison(A, B, greater) :- A > B.
您不需要前端谓词foo/3
。您可以这样阅读这些内容:“comparison
A
B
<Value>
A
<relation>
B
comparison/3
?- comparison(1,3, X).
X = less ;
false.
{{1}} }}“。该程序由描述规则{{1}}的三个规则组成。 '3'表示此规则定义了作为参数赋予它的3个元素之间的关系。
您可以查询此程序:
{{1}}
答案 1 :(得分:0)
你有多个规则吗?
sub(0,0).
sub(E,C) :- C is E/abs(E).
如果您为A-B
传递0,那么这将始终与第一条规则匹配,C
将与0统一。您在技术上只需要一个is
并且您正在使用基础案例定义这个。要使其与规则顺序无关,您也可以在E \= 0
条款中,但我不知道这是否会验证is
,因为\=
(不统一)基本上是相同的事情(没有双关语意)但任何基础术语不仅仅是int。
答案 2 :(得分:0)
也许我误解了,但为什么你不能这样做:
foo(A, B, 1) :- A > B.
foo(A, B, -1) :- A < B.
foo(A, B, 0) :- A =:= B.
即将'C'的值直接嵌入为输出参数。
?- foo(1,3,C).
C = -1 .
?- foo(2,2,C).
C = 0.
如果您已经拥有不需要计算的C值,则无需将其声明为变量?
答案 3 :(得分:0)
Prolog中的算术 - 出于效率原因 - 以“传统”,命令式方式处理。 但是当我们可以限制计算领域时,我们可以使用一些库来提高语言的水平,并重新获得一些丢失的声明性......
例如,在SWI-Prolog中,库(clpfd) - 限于整数域 - 将允许编写
:- [library(clpfd)].
foo(A,B,C) :-
A #> B #<==> C #= 1,
A #< B #<==> C #= -1,
A #= B #<==> C #= 0.
这是A,B,C之间相当普遍的关系。例如
1 ?- foo(1,2,C).
C = -1.
2 ?- foo(2,1,C).
C = 1.
3 ?- foo(2,X,1).
X in inf..1,
X+1#=_G219,
_G219 in inf..2.
4 ?- foo(X,Y,1).
X#\=Y,
X+1#=_G519,
X#>=_G531,
Y#=<_G519+ -1,
Y+1#=_G531.
查询3和4显示了库提供的通用性(我将inf
视为-infinity),显示了从实例化模式推导出的残差约束 - 当然还有我们自己的方程式。
无论如何,我会以这种方式在普通的Prolog中翻译你的代码
foo(A,B,C) :-
A > B, C is 1 ;
A < B, C is -1 ;
A =:= B, C is 0.
需要A,B实例化为数字表达式。
注意我保持不变是/ 2。这样,如果C被实例化为算术表达式,它将按预期工作......
答案 4 :(得分:0)
你为什么不写一个明显的单行?
foo(A,B,C) :- C is truncate(sign(A-B)).
他们都是ISO序言的一部分:
sign/1
如果Expr&lt; 将[s]评估为-1 0,1,如果Expr>如果Expr = 0,则为0和0.如果Expr求值为float,则返回值为float(例如,-1.0,0.0或1.0)。特别要注意,符号(-0.0)的计算结果为0.0。
truncate/1
左截断[s] Expr为整数。如果Expr> = 0,则与floor(Expr)相同。对于Expr&lt; 0这与ceil(Expr)相同。也就是说,截断/ 1向零舍入。
这要求A
和B
都绑定到数值(浮点或整数,或混合)。
如果你想在任何类型的prolog术语中概括这一点,那么就像这样:
foo(A,B, 1 ) :- A @> B .
foo(A,B, 0 ) :- A == B .
foo(A,B, -1 ) :- A @< B .
您会发现使用这些运算符有时会产生奇怪的结果(例如,您会发现-1.0 @< 1
是true
。如果您想强制执行更多“正常”你有数字时的语义,然后当两个术语都是数字时你想要劫持这个案例:
foo(A,B, C ) :- number(A), number(B), ! , C is truncate(sign(A-B)) .
foo(A,B, 1 ) :- A @> B .
foo(A,B, 0 ) :- A == B .
foo(A,B, -1 ) :- A @< B .