Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Prolog 序言:我被困在一种命令式思维中_Prolog_Declarative Programming - Fatal编程技术网

Prolog 序言:我被困在一种命令式思维中

Prolog 序言:我被困在一种命令式思维中,prolog,declarative-programming,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 foo(A,B,C) 如果(A>B)C为1 如果(A0,C为1。 sub(E,C):-E=0,这与地板(Expr)相同。对于Expr

我正在上一堂关于编程范例的课。目前我们正在学习Prolog,我被困在一个不同的范例中。我试图从命令式转换的函数之一是一个相对简单的函数

foo(A,B,C)
    if(A > B) C is 1
    if(A < B) C is -1
    if(A = B) C is 0
foo(A,B,C)
如果(A>B)C为1
如果(A
我可以很容易地在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.
foo(A,B,C):-sub(A-B,C)。
子(E,C):-E=0,C为0。
sub(E,C):-E>0,C为1。
sub(E,C):-E<0,C为-1。
问题是,我只能在整个谓词中使用一个“是”(不能定义一个较小的谓词来调用is和this或其他任何东西),并且我不能使用Prolog的if/else构造。我不知道如何用陈述的方式来思考这个问题


我想也许我可以做一些像C is(A-B)/abs(A-B)的事情,但这会在A=B时中断,需要2个“is”语句。我被卡住了。

你能有多条规则吗

sub(0,0).
sub(E,C) :- C is E/abs(E).

如果将0传递给
A-B
,并且
C
将统一为0,则这将始终与第一条规则匹配。从技术上讲,您只需要一个
is
,并且您正在使用基本案例来定义它。为了使它独立于规则顺序,您也可以通过子句
E\=0
,但我不知道这是否会验证
,因为
\=
(不统一)本质上是相同的东西(没有双关语),但为了声明性编程,它有任何基本术语,而不仅仅是int.

,我们必须考虑我们试图声明的内容,然后才能描述它。为此,我将尝试编写谓词,以便它表示为什么
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(A, B, 1) :- A > B.
foo(A, B, -1) :- A < B.
foo(A, B, 0) :- A =:= B.

如果您已经有了不需要计算的C值,那么就没有必要将其声明为变量?

出于效率原因,Prolog中的算术是以“传统的”命令式方式处理的。 但是当我们可以限制计算领域时,我们可以使用一些库来提高语言的水平,并恢复一些失去的声明性

例如,在SWI Prolog中,library()-限制为整数域-将允许写入

:- [library(clpfd)].

foo(A,B,C) :-
    A #> B #<==> C #= 1,
    A #< B #<==> C #= -1,
    A #= B #<==> C #= 0.
这需要将A,B实例化为数值表达式


注1未作改动的是/2。这样,如果C被实例化为一个算术表达式,它将按预期工作…

为什么不直接编写一行代码呢

foo(A,B,C) :- C is truncate(sign(A-B)).
它们都是ISO序言的一部分:

  • 符号/1

    如果Expr<0,则将[s]计算为-1;如果Expr>0,则将[s]计算为1;如果Expr=0,则将[s]计算为0。如果Expr的计算结果为浮点,则返回值为浮点(例如,-1.0、0.0或1.0)。特别要注意的是,符号(-0.0)的计算结果为0.0

  • truncate/1

    将[s]Expr截断为整数。如果Expr>=0,这与地板(Expr)相同。对于Expr<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 .

这几乎奏效,但有一个重大问题我不知道如何处理。如果我通过sub(A-B,C)并且A-B的计算结果为0,prolog不会对其进行计算,而是转到第二个事实/子目标,并且在除以0时失败。你怎么能避开这个?
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.
foo(A,B,C) :-
    A > B, C is 1 ;
    A < B, C is -1 ;
    A =:= B, C is 0.
foo(A,B,C) :- C is truncate(sign(A-B)).
foo(A,B,  1 ) :- A @> B .
foo(A,B,  0 ) :- A == B .
foo(A,B, -1 ) :- A @< B .
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 .