SWI Пролог foreach / 2 - PullRequest
       22

SWI Пролог foreach / 2

1 голос
/ 08 ноября 2019

Рассмотрим

?- 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 - более аккуратный способ выражения "всего содержимого".

Я попытался добавить некоторые записи в журнал для отладки, но я не могу понять, как это сделать.

?- 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))).

Это просто немного неуклюже. Возможно, специфика хорошая,хотя.)

Использование SWI-Prolog версии 8.0.3 для x64-win64.

1 Ответ

0 голосов
/ 08 ноября 2019

Документация фактически говорит о том, что, по вашему мнению, происходит:

Каждый член соединения является копией цели, где переменные, которые он разделяет с Генератором, заполняютсязначения из соответствующего решения.

Никто не видит большого применения foreach/2;forall/2, я полагаю, чаще используется, но ни один из них не является стандартным. Глядя на документы по forall/2, я замечаю следующее примечание:

Если вы намерены создать привязки переменных, структура управления forall / 2 неадекватна. Возможно, вы ищете maplist / 2, findall / 3 или 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 следует использовать чаще.

...