SWI 序言 foreach/2
SWI Prolog foreach/2
考虑
?- length(L, 4), foreach(member(M,L),(length(M,4))).
L = [_28602, _28608, _28614, _28620].
对
?- length(L, 4), foreach(between(1,4,I),call({L}/[I]>>(nth1(I,L,M),length(M,4)),I)).
L = [[_6010, _6016, _6022, _6028], [_6358, _6364, _6370, _6376], [_6754, _6760, _6766, _6772], [_7198, _7204, _7210, _7216]].
我想得到后一个结果,但是使用 member
是表达 "all the contents".
的更简洁的方式
我试过添加一些日志记录来调试,但我无法弄清它的正反面。
?- length(L, 4), foreach((member(M,L),write(M),writeln(L)),(length(M,4))).
_3400[_3400,_4060,_4066,_4072]
_3400[_4054,_3400,_4066,_4072]
_3400[_4054,_4060,_3400,_4072]
_3400[_4054,_4060,_4066,_3400]
L = [_4054, _4060, _4066, _4072].
还有更复杂的日志记录和修改:
?- length(L, 3), foreach((member(M,L),write((m,M," ")),write((l,L," ")),length(M,3),write((m,M," ")),writeln((l,L))),(true)).
m,_60830, l,[_60830,_61872,_61878], m,[_61944,_61950,_61956], l,[[_61944,_61950,_61956],_61872,_61878]
m,_60830, l,[_61866,_60830,_61878], m,[_61944,_61950,_61956], l,[_61866,[_61944,_61950,_61956],_61878]
m,_60830, l,[_61866,_61872,_60830], m,[_61944,_61950,_61956], l,[_61866,_61872,[_61944,_61950,_61956]]
L = [_61866, _61872, _61878].
这最后一点让我怀疑生成器中的任何变量(foreach
的第一项)在 foreach
被调用时被有效地深度复制,并且副本在每个循环中重置。它会保留已经绑定的结构,但是在 foreach
中统一它们中的任何结构只会统一副本,而不是原始结构。这是一个正确的推论吗?关于 foreach
的运作方式,还有其他我应该知道的信息吗?文档非常薄。
(我确实想出了一个方法来做我本来想做的事情,我想:
loop(Gen, Cond) :-
aggregate(bag(X),call(Gen,X),L),maplist(Cond,L).
?- length(L,4),loop({L}/[X]>>(member(X,L)),[X]>>(length(X,4))).
只是有点笨拙。不过,也许特异性很好。)
为 x64-win64 使用 SWI-Prolog 版本 8.0.3。
The documentation 实际上说的是你认为正在发生的事情:
Each member of the conjunction is a copy of Goal, where the variables it shares with Generator are filled with the values from the corresponding solution.
foreach/2
的用处不多; forall/2
是,我相信,更常用,但这些都不是标准的。查看 forall/2
的文档,我注意到这条注释:
If your intent is to create variable bindings, the forall/2 control structure is inadequate. Possibly you are looking for maplist/2, findall/3 or foreach/2.
果然,我们可以用 maplist/2
和 lamba 表达式来做你想做的事:
?- length(L, 4), maplist([X]>>(length(X,4)), L).
L = [[_9462, _9468, _9474, _9480],
[_9558, _9564, _9570, _9576],
[_9654, _9660, _9666, _9672],
[_9750, _9756, _9762, _9768]].
您也可以使用 findall/3
:
?- length(L, 4), findall(X, (member(X, L), length(X, 4)), Xs).
L = [_10432, _10438, _10444, _10450],
Xs = [[_10580, _10586, _10592, _10598],
[_10550, _10556, _10562, _10568],
[_10520, _10526, _10532, _10538],
[_10490, _10496, _10502, _10508]].
请注意,在后一种情况下,结果不是 L,而是 Xs。
我认为这些中的任何一个都是比您提出的代码更好的选择,虽然我认为 aggregate
应该更频繁地使用,但我觉得它看起来有点复杂。
考虑
?- length(L, 4), foreach(member(M,L),(length(M,4))).
L = [_28602, _28608, _28614, _28620].
对
?- length(L, 4), foreach(between(1,4,I),call({L}/[I]>>(nth1(I,L,M),length(M,4)),I)).
L = [[_6010, _6016, _6022, _6028], [_6358, _6364, _6370, _6376], [_6754, _6760, _6766, _6772], [_7198, _7204, _7210, _7216]].
我想得到后一个结果,但是使用 member
是表达 "all the contents".
我试过添加一些日志记录来调试,但我无法弄清它的正反面。
?- length(L, 4), foreach((member(M,L),write(M),writeln(L)),(length(M,4))).
_3400[_3400,_4060,_4066,_4072]
_3400[_4054,_3400,_4066,_4072]
_3400[_4054,_4060,_3400,_4072]
_3400[_4054,_4060,_4066,_3400]
L = [_4054, _4060, _4066, _4072].
还有更复杂的日志记录和修改:
?- length(L, 3), foreach((member(M,L),write((m,M," ")),write((l,L," ")),length(M,3),write((m,M," ")),writeln((l,L))),(true)).
m,_60830, l,[_60830,_61872,_61878], m,[_61944,_61950,_61956], l,[[_61944,_61950,_61956],_61872,_61878]
m,_60830, l,[_61866,_60830,_61878], m,[_61944,_61950,_61956], l,[_61866,[_61944,_61950,_61956],_61878]
m,_60830, l,[_61866,_61872,_60830], m,[_61944,_61950,_61956], l,[_61866,_61872,[_61944,_61950,_61956]]
L = [_61866, _61872, _61878].
这最后一点让我怀疑生成器中的任何变量(foreach
的第一项)在 foreach
被调用时被有效地深度复制,并且副本在每个循环中重置。它会保留已经绑定的结构,但是在 foreach
中统一它们中的任何结构只会统一副本,而不是原始结构。这是一个正确的推论吗?关于 foreach
的运作方式,还有其他我应该知道的信息吗?文档非常薄。
(我确实想出了一个方法来做我本来想做的事情,我想:
loop(Gen, Cond) :-
aggregate(bag(X),call(Gen,X),L),maplist(Cond,L).
?- length(L,4),loop({L}/[X]>>(member(X,L)),[X]>>(length(X,4))).
只是有点笨拙。不过,也许特异性很好。)
为 x64-win64 使用 SWI-Prolog 版本 8.0.3。
The documentation 实际上说的是你认为正在发生的事情:
Each member of the conjunction is a copy of Goal, where the variables it shares with Generator are filled with the values from the corresponding solution.
foreach/2
的用处不多; forall/2
是,我相信,更常用,但这些都不是标准的。查看 forall/2
的文档,我注意到这条注释:
If your intent is to create variable bindings, the forall/2 control structure is inadequate. Possibly you are looking for maplist/2, findall/3 or foreach/2.
果然,我们可以用 maplist/2
和 lamba 表达式来做你想做的事:
?- length(L, 4), maplist([X]>>(length(X,4)), L).
L = [[_9462, _9468, _9474, _9480],
[_9558, _9564, _9570, _9576],
[_9654, _9660, _9666, _9672],
[_9750, _9756, _9762, _9768]].
您也可以使用 findall/3
:
?- length(L, 4), findall(X, (member(X, L), length(X, 4)), Xs).
L = [_10432, _10438, _10444, _10450],
Xs = [[_10580, _10586, _10592, _10598],
[_10550, _10556, _10562, _10568],
[_10520, _10526, _10532, _10538],
[_10490, _10496, _10502, _10508]].
请注意,在后一种情况下,结果不是 L,而是 Xs。
我认为这些中的任何一个都是比您提出的代码更好的选择,虽然我认为 aggregate
应该更频繁地使用,但我觉得它看起来有点复杂。