您的问题本质上=:=/2
是用于测试而不是建立绑定,尽管is/2
仍然没有真正做到您想要的。例如,while2 is 1 + 1
为真,2 is X+1
不会导致X
绑定到 1,因为is/2
期望左侧只有一个变量或值,右侧只有一个表达式,并且它的行为不像 Prolog 的其余部分那样“关系”。如果您想要以这种方式运行的算术,您应该查看clpfd
; 查看它增加的复杂性可以很好地解释为什么事情是这样的。
幸运的是,您不需要所有的算术来解决您的问题。内置将succ/2
完全满足您的需要,并且奖励,您将获得一个单行解决方案:
inc(X, Y) :- maplist(succ, X, Y).
正在使用:
?- inc([1,2,3], [2,3,4]).
true.
?- inc([1,2,3], X).
X = [2, 3, 4].
?- inc(X, [1,2,3]).
X = [0, 1, 2].
如果您使用succ/2
而不是,您的代码也可以正常工作=:=/2
:
inc([], []).
inc([X|XS],[Y|YS]) :-
succ(X, Y),
inc(XS,YS).
这一定是您怀疑的“简单修复”。:)
我不确定@mbratch 指的是一个谓词的“变量太多”。我怀疑这是他们对 Prolog 的误解,也许是其他语言的保留,其中函数可以返回一个值或其他东西。这里没有技术限制;谓词可以采用任意数量的基础或非基础参数,并根据需要绑定任意数量的参数;限制因素是你的创造力。
同样,我不认为“不对称”在这里是一个有意义的概念。定义只有一个实例化模式的谓词是很正常的,但创建对实例化灵活的谓词也是正常和可取的——你无法提前知道未来可能需要什么用途。您可能会认为破坏信息的实例化模式可能会排除逆实例化模式,但实际上,您通常可以将其转换为生成器。
举一个老生常谈的例子,append/3
的名字似乎暗示了这种模式:
?- append([1,2], [3,4], X).
X = [1,2,3,4]
这是一个非常好的用途,但也是如此:
?- append(X, Y, [1,2,3,4]).
这是一种不确定的实例化模式,将产生五种解决方案:
X = [], Y = [1,2,3,4]
X = [1], Y = [2,3,4]
X = [1,2], Y = [3,4]
X = [1,2,3], Y = [4]
X = [1,2,3,4], Y = []
这似乎与@mbratch 的一些想法相矛盾,但是在通常的定义中没有明确测试接地/非接地append/3
,因为这不是必需的,同样使用第二种调用模式,您可以从其中获得两个“返回值”一个输入。SWI 来源:
append([], L, L).
append([H|T], L, [H|R]) :-
append(T, L, R).
编辑:负数。我忘记了succ/2
仅在正整数上定义。我们可以应用@mbratch 的技术,仍然得到一个具有所需属性的整洁解决方案:
isucc(X, Y) :- var(X), X is Y-1.
isucc(X, Y) :- Y is X+1.
inc(X, Y) :- maplist(isucc, X, Y).
在行动:
?- inc(X, [-1,2]).
X = [-2, 1] ;
false.
编辑:使用 clp(fd) (通过@mat):
fdsucc(X,Y) :- Y #= X + 1.
inc(X, Y) :- maplist(fdsucc, X, Y).
即使对于最一般的查询,这也会生成:
?- inc(X, Y).
X = Y, Y = [] ;
X = [_G467],
Y = [_G476],
_G467+1#=_G476 ;
X = [_G610, _G613],
Y = [_G622, _G625],
_G610+1#=_G622,
_G613+1#=_G625 ;
X = [_G753, _G756, _G759],
Y = [_G768, _G771, _G774],
_G753+1#=_G768,
_G756+1#=_G771,
_G759+1#=_G774
...
这样做的实用性值得怀疑,但大概因为您使用的是 clp(fd) ,您最终会施加其他约束并获得有用的东西。