这应该是一个简单的解决方案,但我似乎无法解决这个问题,而且令人沮丧。我编写了一个程序,用于计算或验证两个列表是否相关,因为第二个列表的元素都是从第一个列表的元素中加1。这在给出两个列表时有效,但在需要计算列表时则不行。
代码如下:
inc([], []).
inc([X|XS],[Y|YS]) :-
Y =:= X+1,
inc(XS,YS).
ERROR: =:=/2: Arguments are not sufficiently instantiated
非常感谢任何帮助!
答案 0 :(得分:1)
你的问题基本上是=:=/2
用于测试而不是建立绑定,尽管is/2
仍然没有真正做你想要的。例如,虽然2 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
的通常定义中没有对ground / nonground的明确测试,因为它没有必要,同样对于第二个调用模式你从一个输入中得到两个“返回值”。 SWI source:
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),你最终会施加其他限制并获得有用的东西。
答案 1 :(得分:0)
inc([],[]).
inc([X|XS],[Y|YS]) :-
nonvar(X),
Z is X + 1,
Y = Z,
inc(XS,YS), !.
inc([X|XS],[Y|YS]) :-
nonvar(Y),
Z is Y - 1,
X = Z,
inc(XS,YS), !.
这里我们需要为加法得到一个真实的计算,然后用=来尝试实例化。必须对谓词进行拆分以处理X未实例化的情况,而不是Y的情况。每个末尾的!
是为了防止它在找到两个相似路径中的一个之后尝试更多解决方案。