0

这应该很容易解决,但我似乎无法解决这个问题,而且越来越令人沮丧。我编写了一个程序来计算或验证两个列表是否相关,因为第二个列表的元素都从第一个列表的元素中增加了一个。这在给定两个列表时有效,但在需要计算列表时无效。

代码如下:

inc([], []).
inc([X|XS],[Y|YS]) :- 
  Y =:= X+1,
  inc(XS,YS).
ERROR: =:=/2: Arguments are not sufficiently instantiated

任何帮助将不胜感激!

4

2 回答 2

1

您的问题本质上=:=/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) ,您最终会施加其他约束并获得有用的东西。

于 2013-05-29T05:09:45.037 回答
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 的情况。每个!末尾的 是为了防止它在通过两条相似路径之一找到一个之后尝试更多解决方案。

于 2013-05-29T03:25:17.523 回答