Примитив suspend / 3 может связывать цель только с переменными, которые уже существуют во время ожидания.Но когда список создается постепенно (спереди назад), переменная "tail" существующего списка становится экземпляром, и расширенный список теперь имеет новую переменную "tail".Это приводит к поведению, которое вы видите, когда цель просыпается сразу после создания первого элемента списка:
?- suspend(writeln(now:Xs), 0, Xs->inst), length(Xs, 5).
now : [_510|_511]
Xs = [_510, _520, _522, _524, _526]
Yes (0.00s cpu)
Если вы хотите дождаться завершения списка, используйте следующую схему, гдевы повторно приостанавливаете каждый раз, когда сталкиваетесь с необоснованным хвостом списка:
write_complete_list(Xs) :-
write_complete_list(Xs, Xs).
write_complete_list(Xs, Ts) :- var(Ts), !,
suspend(write_complete_list(Xs,Ts), 0, Ts->inst).
write_complete_list(Xs, [_|Ts]) :-
write_complete_list(Xs, Ts).
write_complete_list(Xs, []) :- % Xs is now a complete list
writeln(now:Xs).
, который ведет себя как нужно
?- write_complete_list(Xs), length(Xs, 5).
now : [_514, _542, _570, _598, _626]
Xs = [_514, _542, _570, _598, _626]
Yes (0.00s cpu)
В качестве альтернативы, если вы используете последнюю версию ECLiPSe, вы можете использовать eval_to_complete_list / 2 .В этом примере он будет распространять постепенно построенный список Ys
на вспомогательную переменную Xs
, как только завершится Ys
, что, в свою очередь, вызывает приостановленную цель:
?- suspend(writeln(now:Xs), 0, Xs->inst), eval_to_complete_list(Ys, Xs), length(Ys, 5).
now : [_597, _626, _655, _684, _713]
Xs = [_597, _626, _655, _684, _713]
Ys = [_597, _626, _655, _684, _713]
Yes (0.00s cpu)