谓词 nb_setarg/3 的意外结果
Unexpected result for predicate nb_setarg/3
有谁知道谓词 nb_setarg/3
在 SWI-Prolog 解释器 (v. 8.2.1) 的顶层与谓词 forall/3
一起使用时无法正常工作的原因?
在顶层输入的目标中使用时的工作原理:
?-
functor(A, array, 5),
forall(arg(Index, A, _),
nb_setarg(Index, A, 0)).
A = array(_26341340, _26341342, _26341344, _26341346, _26341348).
在规则中使用时的工作原理:
new_array(A,N) :-
functor(A, array, N),
forall(
arg(Index, A, _),
nb_setarg(Index, A, 0)).
然后:
?-
new_array(A,5).
A = array(0, 0, 0, 0, 0).
我不知道,但是在顶层,由于某种原因(SWI-Prolog 8.3.14),复合项的修改在回溯时被回滚:
顶级
?-
functor(A, array, 5),
forall(
arg(Index, A, _),
(format("~q: ~q\n",[Index,A]),
nb_setarg(Index, A, 0),
format("~q: ~q\n",[Index,A]))).
然后我们在 forall
的每个段落中看到带有新变量的新 array/5
复合术语
1: array(_3228,_4334,_4336,_4338,_4340)
1: array(0 ,_4334,_4336,_4338,_4340)
2: array(_4332,_3228,_4336,_4338,_4340)
2: array(_4332,0, _4336,_4338,_4340)
3: array(_4332,_4334,_3228,_4338,_4340)
3: array(_4332,_4334, 0,_4338,_4340)
4: array(_4332,_4334,_4336,_3228,_4340)
4: array(_4332,_4334,_4336,0, _4340)
5: array(_4332,_4334,_4336,_4338,_3228)
5: array(_4332,_4334,_4336,_4338,0)
A = array(_4332, _4334, _4336, _4338, _4340).
一般
new_array(A,N) :-
functor(A, array, N),
forall(
arg(Index, A, _),
(format("~q: ~q\n",[Index,A]),
nb_setarg(Index, A, 0),
format("~q: ~q\n",[Index,A]))).
然后:
?- new_array(A,5).
1: array(_2498,_2500,_2502,_2504,_2506)
1: array(0,_2500,_2502,_2504,_2506)
2: array(0,_2500,_2502,_2504,_2506)
2: array(0,0,_2502,_2504,_2506)
3: array(0,0,_2502,_2504,_2506)
3: array(0,0,0,_2504,_2506)
4: array(0,0,0,_2504,_2506)
4: array(0,0,0,0,_2506)
5: array(0,0,0,0,_2506)
5: array(0,0,0,0,0)
A = array(0, 0, 0, 0, 0).
另一方面,the implementation如下:
forall(Cond, Action) :-
\+ (Cond, \+ Action).
上面的谓词不适合用作循环。
但是,“规则设置”中的行为似乎是正确的。
The predicate forall/2
is implemented as \+ ( Cond, \+ Action)
, i.e., There is no instantiation of Cond
for which Action
is false. The use of double negation implies that forall/2
does not change any variable bindings. It proves a relation. The forall/2
control structure can be used for its side-effects.
确实如此。
nb_setarg/3
的描述也没什么特别的
就好像 nb_setarg/3
在顶层作为 setarg/3
工作?
跟踪没有显示任何内容:
^ Call: (13) format("~q: ~q\n", [1, array(_30756, _32086, _32088, _32090, _32092)]) ? creep
1: array(_30756,_32086,_32088,_32090,_32092)
^ Exit: (13) format("~q: ~q\n", [1, array(_30756, _32086, _32088, _32090, _32092)]) ? creep
Call: (13) setarg(1, array(_30756, _32086, _32088, _32090, _32092), 0) ? creep
Exit: (13) setarg(1, array(0, _32086, _32088, _32090, _32092), 0) ? creep
^ Call: (13) format("~q: ~q\n", [1, array(0, _32086, _32088, _32090, _32092)]) ? creep
1: array(0,_32086,_32088,_32090,_32092)
^ Exit: (13) format("~q: ~q\n", [1, array(0, _32086, _32088, _32090, _32092)]) ? creep
Next "forall" passage: we are using a new compound term!
^ Call: (13) format("~q: ~q\n", [2, array(_32084, _30756, _32088, _32090, _32092)]) ? creep
2: array(_32084,_30756,_32088,_32090,_32092)
^ Exit: (13) format("~q: ~q\n", [2, array(_32084, _30756, _32088, _32090, _32092)]) ? creep
Call: (13) setarg(2, array(_32084, _30756, _32088, _32090, _32092), 0) ? creep
Exit: (13) setarg(2, array(_32084, 0, _32088, _32090, _32092), 0) ?
由于它与 SWI-Prolog 相关,您可能想在 Discourse 上提问。
更新
在 GNU Prolog 在线试过。
GNU Prolog 要求实例化 arg/3
的索引并且没有 nb_setarg/3
(也没有 forall/2
??)。
但是让我们在 SWI-Prolog 中尝试以下操作:
functor(A, array, 5),
\+ (
between(1,5,Index),arg(Index, A, _),
\+
(format("~q: ~q\n",[Index,A]),
nb_setarg(Index, A, 0),
format("~q: ~q\n",[Index,A]))).
也不行。
更新:尝试更简单和精简的东西
符合预期:
?-
A=p(1,2,3),nb_setarg(1,A,foo).
A = p(foo, 2, 3).
带有双重否定。还保留不可回溯设置的值:
?-
A=p(1,2,3),\+ \+ nb_setarg(1,A,foo).
A = p(foo, 2, 3).
我认为这可能是一个错误。但它可能不是 forall/2
或 nb_setarg/3
中的错误(只是)。因为这有效:
?- A = array(_, _, _, _, _), forall(arg(Index, A, _), nb_setarg(Index, A, 0)).
A = array(0, 0, 0, 0, 0).
而您的示例没有 (SWI 7.6.4):
?- functor(A, array, 5), forall(arg(Index, A, _), nb_setarg(Index, A, 0)).
A = array(_2290, _2292, _2294, _2296, _2298).
Jan Wielemaker 在 issue #733 中说(“从 forall/2 调用,nb_setarg/3 应用于顶级目标中构造的复合项没有效果(它变成setarg/3?") 这是一个已知问题:
The problem boils down to:
?- functor(C, a, 2),
\+ \+ (arg(1, C, x),
nb_setarg(1, C, foo)).
C = a(_52710, _52712).
I.e., if there is an earlier trailed assignment on the target location,
backtracking to before this trailed assignment turns the location back into a
variable. In this case the arg(I,Term,_)
unifies the target with the variable
in the toplevel query term. As this is older, the target location becomes a
trailed reference to the query variable.
nb_setarg/3
is useful, but a can of worms.
...
I'd have to do a lot of research to find [what is going wrong].
Tracking all the trailing and optimization thereof is non-trivial.
Basically, do not backtrack to before where you started using nb_*
and only
use the nb_*
predicates on the same location.
所以这个想法似乎是轨迹(即,如果我理解正确的话,在回溯时要回滚的修改堆栈)包含一个赋值(arg(1, C, x)
),用于精确修改的位置nb_setarg/3
并且您回溯到 之前的作业 ,您的不可回溯作业丢失了。
有道理,这样看
A = array(_26341340, _26341342, _26341344, _26341346, _26341348).
实际上是正确的结果。
(在逻辑Prolog和赋值-Prolog之间切换让我头疼)。
我猜是这样做的:
A=array(_,_,_,_,_),
forall(
between(1,5,Index),
nb_setarg(Index, A, bar)).
或
functor(A, array, 5),
forall(
between(1,5,Index),
nb_setarg(Index, A, bar)).
在尝试了以下查询之后,我怀疑谓词 functor/3
(或其合理化版本 compound_name_arity/3
)是 nb_setarg/3
所观察到的问题的真正根源。它似乎创建了一个包含新变量的术语,这些变量“不在顶级查询的范围内”(请注意,当变量名称明确出现在查询中时,结果符合预期)。
?- A =.. [array,X1,X2,X3],
forall( arg(I, A, _),
nb_setarg(I, A, 0) ).
A = array(0,0,0)
?- compound_name_arguments(A, array, [X1,X2,X3]),
forall( arg(I, A, _),
nb_setarg(I, A, 0) ).
A = array(0,0,0)
?- compound_name_arity(A, array, 3),
forall( arg(I, A, _),
nb_setarg(I, A, 0) ).
A = array(_20928, _20930, _20932)
?- functor(A, array, 3),
forall( arg(I, A, _),
nb_setarg(I, A, 0) ).
A = array(_22056, _22058, _22060).
有谁知道谓词 nb_setarg/3
在 SWI-Prolog 解释器 (v. 8.2.1) 的顶层与谓词 forall/3
一起使用时无法正常工作的原因?
在顶层输入的目标中使用时的工作原理:
?-
functor(A, array, 5),
forall(arg(Index, A, _),
nb_setarg(Index, A, 0)).
A = array(_26341340, _26341342, _26341344, _26341346, _26341348).
在规则中使用时的工作原理:
new_array(A,N) :-
functor(A, array, N),
forall(
arg(Index, A, _),
nb_setarg(Index, A, 0)).
然后:
?-
new_array(A,5).
A = array(0, 0, 0, 0, 0).
我不知道,但是在顶层,由于某种原因(SWI-Prolog 8.3.14),复合项的修改在回溯时被回滚:
顶级
?-
functor(A, array, 5),
forall(
arg(Index, A, _),
(format("~q: ~q\n",[Index,A]),
nb_setarg(Index, A, 0),
format("~q: ~q\n",[Index,A]))).
然后我们在 forall
array/5
复合术语
1: array(_3228,_4334,_4336,_4338,_4340)
1: array(0 ,_4334,_4336,_4338,_4340)
2: array(_4332,_3228,_4336,_4338,_4340)
2: array(_4332,0, _4336,_4338,_4340)
3: array(_4332,_4334,_3228,_4338,_4340)
3: array(_4332,_4334, 0,_4338,_4340)
4: array(_4332,_4334,_4336,_3228,_4340)
4: array(_4332,_4334,_4336,0, _4340)
5: array(_4332,_4334,_4336,_4338,_3228)
5: array(_4332,_4334,_4336,_4338,0)
A = array(_4332, _4334, _4336, _4338, _4340).
一般
new_array(A,N) :-
functor(A, array, N),
forall(
arg(Index, A, _),
(format("~q: ~q\n",[Index,A]),
nb_setarg(Index, A, 0),
format("~q: ~q\n",[Index,A]))).
然后:
?- new_array(A,5).
1: array(_2498,_2500,_2502,_2504,_2506)
1: array(0,_2500,_2502,_2504,_2506)
2: array(0,_2500,_2502,_2504,_2506)
2: array(0,0,_2502,_2504,_2506)
3: array(0,0,_2502,_2504,_2506)
3: array(0,0,0,_2504,_2506)
4: array(0,0,0,_2504,_2506)
4: array(0,0,0,0,_2506)
5: array(0,0,0,0,_2506)
5: array(0,0,0,0,0)
A = array(0, 0, 0, 0, 0).
另一方面,the implementation如下:
forall(Cond, Action) :-
\+ (Cond, \+ Action).
上面的谓词不适合用作循环。
但是,“规则设置”中的行为似乎是正确的。
The predicate
forall/2
is implemented as\+ ( Cond, \+ Action)
, i.e., There is no instantiation ofCond
for whichAction
is false. The use of double negation implies thatforall/2
does not change any variable bindings. It proves a relation. Theforall/2
control structure can be used for its side-effects.
确实如此。
nb_setarg/3
的描述也没什么特别的
就好像 nb_setarg/3
在顶层作为 setarg/3
工作?
跟踪没有显示任何内容:
^ Call: (13) format("~q: ~q\n", [1, array(_30756, _32086, _32088, _32090, _32092)]) ? creep
1: array(_30756,_32086,_32088,_32090,_32092)
^ Exit: (13) format("~q: ~q\n", [1, array(_30756, _32086, _32088, _32090, _32092)]) ? creep
Call: (13) setarg(1, array(_30756, _32086, _32088, _32090, _32092), 0) ? creep
Exit: (13) setarg(1, array(0, _32086, _32088, _32090, _32092), 0) ? creep
^ Call: (13) format("~q: ~q\n", [1, array(0, _32086, _32088, _32090, _32092)]) ? creep
1: array(0,_32086,_32088,_32090,_32092)
^ Exit: (13) format("~q: ~q\n", [1, array(0, _32086, _32088, _32090, _32092)]) ? creep
Next "forall" passage: we are using a new compound term!
^ Call: (13) format("~q: ~q\n", [2, array(_32084, _30756, _32088, _32090, _32092)]) ? creep
2: array(_32084,_30756,_32088,_32090,_32092)
^ Exit: (13) format("~q: ~q\n", [2, array(_32084, _30756, _32088, _32090, _32092)]) ? creep
Call: (13) setarg(2, array(_32084, _30756, _32088, _32090, _32092), 0) ? creep
Exit: (13) setarg(2, array(_32084, 0, _32088, _32090, _32092), 0) ?
由于它与 SWI-Prolog 相关,您可能想在 Discourse 上提问。
更新
在 GNU Prolog 在线试过。
GNU Prolog 要求实例化 arg/3
的索引并且没有 nb_setarg/3
(也没有 forall/2
??)。
但是让我们在 SWI-Prolog 中尝试以下操作:
functor(A, array, 5),
\+ (
between(1,5,Index),arg(Index, A, _),
\+
(format("~q: ~q\n",[Index,A]),
nb_setarg(Index, A, 0),
format("~q: ~q\n",[Index,A]))).
也不行。
更新:尝试更简单和精简的东西
符合预期:
?-
A=p(1,2,3),nb_setarg(1,A,foo).
A = p(foo, 2, 3).
带有双重否定。还保留不可回溯设置的值:
?-
A=p(1,2,3),\+ \+ nb_setarg(1,A,foo).
A = p(foo, 2, 3).
我认为这可能是一个错误。但它可能不是 forall/2
或 nb_setarg/3
中的错误(只是)。因为这有效:
?- A = array(_, _, _, _, _), forall(arg(Index, A, _), nb_setarg(Index, A, 0)).
A = array(0, 0, 0, 0, 0).
而您的示例没有 (SWI 7.6.4):
?- functor(A, array, 5), forall(arg(Index, A, _), nb_setarg(Index, A, 0)).
A = array(_2290, _2292, _2294, _2296, _2298).
Jan Wielemaker 在 issue #733 中说(“从 forall/2 调用,nb_setarg/3 应用于顶级目标中构造的复合项没有效果(它变成setarg/3?") 这是一个已知问题:
The problem boils down to:
?- functor(C, a, 2), \+ \+ (arg(1, C, x), nb_setarg(1, C, foo)). C = a(_52710, _52712).
I.e., if there is an earlier trailed assignment on the target location, backtracking to before this trailed assignment turns the location back into a variable. In this case the
arg(I,Term,_)
unifies the target with the variable in the toplevel query term. As this is older, the target location becomes a trailed reference to the query variable.
nb_setarg/3
is useful, but a can of worms.
...
I'd have to do a lot of research to find [what is going wrong]. Tracking all the trailing and optimization thereof is non-trivial. Basically, do not backtrack to before where you started using
nb_*
and only use thenb_*
predicates on the same location.
所以这个想法似乎是轨迹(即,如果我理解正确的话,在回溯时要回滚的修改堆栈)包含一个赋值(arg(1, C, x)
),用于精确修改的位置nb_setarg/3
并且您回溯到 之前的作业 ,您的不可回溯作业丢失了。
有道理,这样看
A = array(_26341340, _26341342, _26341344, _26341346, _26341348).
实际上是正确的结果。
(在逻辑Prolog和赋值-Prolog之间切换让我头疼)。
我猜是这样做的:
A=array(_,_,_,_,_),
forall(
between(1,5,Index),
nb_setarg(Index, A, bar)).
或
functor(A, array, 5),
forall(
between(1,5,Index),
nb_setarg(Index, A, bar)).
在尝试了以下查询之后,我怀疑谓词 functor/3
(或其合理化版本 compound_name_arity/3
)是 nb_setarg/3
所观察到的问题的真正根源。它似乎创建了一个包含新变量的术语,这些变量“不在顶级查询的范围内”(请注意,当变量名称明确出现在查询中时,结果符合预期)。
?- A =.. [array,X1,X2,X3],
forall( arg(I, A, _),
nb_setarg(I, A, 0) ).
A = array(0,0,0)
?- compound_name_arguments(A, array, [X1,X2,X3]),
forall( arg(I, A, _),
nb_setarg(I, A, 0) ).
A = array(0,0,0)
?- compound_name_arity(A, array, 3),
forall( arg(I, A, _),
nb_setarg(I, A, 0) ).
A = array(_20928, _20930, _20932)
?- functor(A, array, 3),
forall( arg(I, A, _),
nb_setarg(I, A, 0) ).
A = array(_22056, _22058, _22060).