Я хочу сгенерировать 3 случайных числа, используя так называемые предикаты «итерация и сбор».
Я собираю комментарии по любой из следующих попыток.
Запись встроенного предиката сбивает с толку и подвержен ошибкам (или, возможно, даже невозможен с is
там?), поэтому мы определяем:
side_effect_and_unify(X) :-
format("Called with ~w\n",X),
X is random(100),
format("Returning with ~w\n",X).
Мы читаем:
Предикат forall/2
(forall(:Cond,:Action)
) реализован как \+ ( Cond, \+ Action)
, т. Е. Нет экземпляра Cond , для которого Action ложно ..
Это должно "отгородить" любые переменные экземпляры вообще. Не удивительно:
?- length(L,3),forall(member(X,L),side_effect_and_unify(X)).
Called with _32964
Returning with 94
Called with _32964
Returning with 36
Called with _32964
Returning with 93
L = [_33490, _33496, _33502].
100% уверены, что невозможно получить эти случайные числа в L
.
Мы читаем:
В отличие от forall/2
, который запускает отказоустойчивый l oop, который доказывает Цель для каждого решения Генератор , foreach/2
создает соединение. Каждый член соединения является копией Goal , где переменные, которые он разделяет с Generator , заполняются значениями из соответствующего решения.
?- length(L,3),foreach(member(X,L),side_effect_and_unify(X)).
Called with _29916
Returning with 33
Called with _29916
Returning with 3
Called with _29916
Returning with 97
L = [_30434, _30440, _30446].
Нет радости, но возможно ли это?
Описание заставляет меня думать, что это то, что работает:
?- L=[L1,L2,L3],side_effect_and_unify(L1),side_effect_and_unify(L2),side_effect_and_unify(L3).
Called with _31202
Returning with 88
Called with _31208
Returning with 81
Called with _31214
Returning with 5
L = [88, 81, 5],
L1 = 88,
L2 = 81,
L3 = 5.
, но, очевидно, нет.
?- length(L,3),findall(X,(member(X,L),side_effect_and_unify(X)),Out).
Called with _28410
Returning with 75
Called with _28410
Returning with 18
Called with _28410
Returning with 66
L = [_29046, _29052, _29058],
Out = [75, 18, 66].
Да!
bagof/3
дружелюбнее, но мы должны сказать, что «не связывай вар L
в цель». Я не совсем уверен относительно значения: очевидно, это означает, что L
является переменной над целью, поэтому она может принимать значение, определенное для L
вне цели.
Хотя здесь мы читаем:
Эта функция светится в сочетании с bagof/3
или setof/3
, где вы обычно должны указывать переменные, в которых связывание, которое вас не интересует, используя конструкцию Var^Goal
(пометив Var
как экзистенциально количественно).
Это будет означать обратное: L
- это свободная переменная внутри цели (но тогда строка ниже не будет работать). Как правильно думать об этом?
?- length(L,3),bagof(X,L^(member(X,L),side_effect_and_unify(X)),Out).
Called with _24336
Returning with 10
Called with _24336
Returning with 24
Called with _24336
Returning with 22
L = [_24912, _24918, _24924],
Out = [10, 24, 22].
Другая специальность bagof/3
основана на замечании здесь :
[это] не ' т копирует условия, которые он накапливает в списке. Это может быть фундаментальным, например, когда ваш список будет собирать атрибутивные переменные, например, те, которые вы используете при моделировании проблемы с библиотекой (clpfd).
Ладно, это просто.
?- length(L,3),maplist(side_effect_and_unify,L).
Called with _26224
Returning with 23
Called with _26230
Returning with 63
Called with _26236
Returning with 70
L = [23, 63, 70].
Не только приятнее, но ИМХО, фактически читабельно читаемо с yall. Вы на самом деле видите метаколл:
?- length(L,3),maplist([X]>>side_effect_and_unify(X),L).
Called with _27420
Returning with 34
Called with _27426
Returning with 41
Called with _27432
Returning with 25
L = [34, 41, 25].