Prolog:我陷入了一种势在必行的心态

时间:2014-03-07 20:25:21

标签: prolog declarative-programming

我正在上课程编程范例。目前我们正在学习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“是”语句。我只是卡住了。

5 个答案:

答案 0 :(得分:1)

为了以声明方式编程,我们必须考虑我们要声明的内容,然后我们可以对其进行描述。为此,我将尝试编写谓词,以便它表示为什么C的值在三种可能状态之间交替,这取决于AB的相对大小。这是一个与您使用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向零舍入。

这要求AB都绑定到数值(浮点或整数,或混合)。

如果你想在任何类型的prolog术语中概括这一点,那么就像这样:

foo(A,B,  1 ) :- A @> B .
foo(A,B,  0 ) :- A == B .
foo(A,B, -1 ) :- A @< B .

您会发现使用这些运算符有时会产生奇怪的结果(例如,您会发现-1.0 @< 1true。如果您想强制执行更多“正常”你有数字时的语义,然后当两个术语都是数字时你想要劫持这个案例:

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 .