为什么length / 2会使我脱离全局堆栈?

时间:2019-05-30 15:28:52

标签: exception prolog clpfd

当我提交查询时:

?- X in 1..2, length(List,X).

返回的结果是:

X = 1, List = [_1260];
X = 2, List = [_1260, _1266];
ERROR: Out of global-stack.
ERROR: No room for exception term. Aborting.
% Execution Aborted

我认为发生这种情况是因为X没有接地,所以我又运行了3个查询来查看length / 2行为如何将非实例化变量作为length:

?- X in inf..sup, length(List,X).
?- length(List,_).
?- length(List,_X).

,一切正常。因此,如果X不接地,则在达到域的最大值后,length / 2会崩溃。为什么会这样呢?它不应该返回 false 吗?

1 个答案:

答案 0 :(得分:2)

  

为什么会这样?它不应该返回false吗?

否,由于length/2不了解这些范围,它只是建议值,而冻结约束检查每次拒绝这些值。

length/2 [swi-doc]可以以“ 建设性”的方式使用。实际上,我们可以生成具有相应长度的列表,例如:

?- length(L, N).
L = [],
N = 0 ;
L = [_2316],
N = 1 ;
L = [_2316, _2322],
N = 2 ;
L = [_2316, _2322, _2328],
N = 3
...

现在,您在N上定义了一个约束,这意味着如果将N设置为某个值,则Prolog解释器将检查该值是否在1..2范围内。因此,对于每个带有N > 2的值,这将失败。但是length/2当然理解这个范围。它将不断建议列表及其相应的长度,并且每次都会失败。

等效于:

?- length(L, N), member(N, [1, 2]).
L = [_2304],
N = 1 ;
L = [_2304, _2310],
N = 2 ;
ERROR: Out of global-stack.
ERROR: No room for exception term. Aborting.

在这里相反地执行此操作更有意义,例如:

?- member(N, [1,2]), length(L, N).
N = 1,
L = [_3372] ;
N = 2,
L = [_3372, _3378].

或者在无法解决的情况下,尝试freeze/2 [swi-doc]构造列表,直到知道N为止。