在Prolog中使用算术运算

在Prolog中使用算术运算,prolog,Prolog,我有以下代码: position(0,0). move(f):- position(X,Y), number(X), number(Y), Y is Y+1, X is X+1. 但是当我调用move(f)时,它返回false。数字(X)和数字(Y)返回true,但当我添加其他两行时,函数不起作用。问题出在哪里?详细阐述您的问题收到的一些评论,Prolog中的变量代表单个值的可能实例化,就像数学和数理逻辑中的变量一样,一旦在上下文中实例化,它们必须保持一

我有以下代码:

position(0,0).
move(f):-
    position(X,Y),
    number(X),
    number(Y),
    Y is Y+1,
    X is X+1.

但是当我调用move(f)时,它返回false。数字(X)和数字(Y)返回true,但当我添加其他两行时,函数不起作用。问题出在哪里?

详细阐述您的问题收到的一些评论,Prolog中的变量代表单个值的可能实例化,就像数学和数理逻辑中的变量一样,一旦在上下文中实例化,它们必须保持一致。如果我们处理的是一个公式
0=(a+b)-(a+b)
,我们知道,只有当分配给第一个
a
的任何值也分配给第二个
时,它才能表达其预期意义。也就是说,我们可以用任何值替换
a
,但它必须始终是相同的值。Prolog以同样的方式处理变量。如果x=x+1,则2=3;但是数学也会被打破

针对mat对使用动态谓词的警告,这里有一种处理移动的可能方法,但通过传递以前移动的列表来实现。使用此方法,最近的移动将始终是复合术语
移动(列表)
中列表的第一个元素

假设当前的移动历史如下:

moves([position(0,0), position(0,1), position(1,1)]).
move/3
采用一个方向,一个表示先前移动的复杂术语,并告诉我们更新的移动列表是什么

move(Direction, moves([From|Ms]), moves([To,From|Ms])) :-
    move_in_direction(Direction,From,To).
沿方向移动/3
获取一个方向和一个位置,并告诉我们该方向的下一个位置是什么:

move_in_direction(left,  position(X1,Y1), position(X2,Y1)) :- X2 is X1 - 1.
move_in_direction(right, position(X1,Y1), position(X2,Y1)) :- X2 is X1 + 1.
move_in_direction(up,    position(X1,Y1), position(X1,Y2)) :- Y2 is Y1 + 1.
move_in_direction(down,  position(X1,Y1), position(X1,Y2)) :- Y2 is Y1 - 1.

请注意,使用此方法,您可以免费获得可追溯的移动历史。我想你可以用一些有趣的方式来使用它——例如,让玩家探索可能的一系列动作,直到满足某个条件,在这一点上它提交或回溯。我很想知道你最终会得到什么样的解决方案。

详细阐述你收到的一些评论,Prolog中的变量代表单个值的可能实例化,就像数学和数理逻辑中的变量一样,一旦它们在上下文中被实例化,它们就必须保持一致。如果我们处理的是一个公式
0=(a+b)-(a+b)
,我们知道,只有当分配给第一个
a
的任何值也分配给第二个
时,它才能表达其预期意义。也就是说,我们可以用任何值替换
a
,但它必须始终是相同的值。Prolog以同样的方式处理变量。如果x=x+1,则2=3;但是数学也会被打破

针对mat对使用动态谓词的警告,这里有一种处理移动的可能方法,但通过传递以前移动的列表来实现。使用此方法,最近的移动将始终是复合术语
移动(列表)
中列表的第一个元素

假设当前的移动历史如下:

moves([position(0,0), position(0,1), position(1,1)]).
move/3
采用一个方向,一个表示先前移动的复杂术语,并告诉我们更新的移动列表是什么

move(Direction, moves([From|Ms]), moves([To,From|Ms])) :-
    move_in_direction(Direction,From,To).
沿方向移动/3
获取一个方向和一个位置,并告诉我们该方向的下一个位置是什么:

move_in_direction(left,  position(X1,Y1), position(X2,Y1)) :- X2 is X1 - 1.
move_in_direction(right, position(X1,Y1), position(X2,Y1)) :- X2 is X1 + 1.
move_in_direction(up,    position(X1,Y1), position(X1,Y2)) :- Y2 is Y1 + 1.
move_in_direction(down,  position(X1,Y1), position(X1,Y2)) :- Y2 is Y1 - 1.

请注意,使用此方法,您可以免费获得可追溯的移动历史。我想你可以用一些有趣的方式来使用它——例如,让玩家探索可能的一系列动作,直到满足某个条件,在这一点上它提交或回溯。我很想知道你最终会采用什么样的解决方案。

f
在哪里
X
Y
完全在该规则内部。规则还规定,
X
Y
必须比它们自身大1。这是一个矛盾,所以永远是错误的。记住它们不是变量,它们不会改变。请说明您对代码的意图,因为从上面看不清楚。要做的是:移动(f):-retract(position(X,Y)),N是Y+1,assert(position(X,N))。使用这样的副作用可以防止您在多个方向上使用谓词,并使分析变得非常复杂,调试和测试代码。最好将
move
视为定义两个位置之间关系的谓词,因此需要两个参数而不是一个参数。例如,使用有限域约束使代码尽可能通用:
移动(位置(X0,Y0),位置(X,Y)):-X#=X0+1,Y#=Y0+1。
如果只有一个或没有一个位置(完全)已知,也可以在所有方向上使用它。这也可以简化其他代码。还要注意,
f
指定一个原子,而不是一个变量。所有变量都大写。但是,不确定当您的谓词在任何语句中都没有引用时,
f
的谓词意味着什么,并且
X
Y
在您的谓词中也没有引用时,
f
在哪里
X
Y
完全在该规则内部。规则还规定,
X
Y
必须比它们自身大1。这是一个矛盾,所以永远是错误的。记住它们不是变量,它们不会改变。请说明您对代码的意图,因为从上面看不清楚。要做的是:移动(f):-retract(position(X,Y)),N是Y+1,assert(position(X,N))。使用这样的副作用可以防止您在多个方向上使用谓词,并使分析变得非常复杂,调试和测试代码。最好将
move
视为定义两个位置之间关系的谓词,因此需要两个参数而不是一个参数。例如,使用有限域约束使代码尽可能通用:
移动(位置(X0,Y0),位置(X,Y)):-X#=X0+1,Y#=Y0+1。
如果只有一个或没有一个位置(完全)已知,也可以在所有方向上使用它