Это было мое первое столкновение с понятием детерминированности в Прологе: noredirect=1#comment84840684_48916791">Почему Prolog не выполняет возврат при сравнении?
Я также нашел это обсуждение интересным: Имеет ли понятие "semidet" в Prolog улажено?
Я хотел реализовать более общую конструкцию цикла (которая ведет себя как findall): (Кстати: источник findall кажется странным, не могу понять, что это за «$....»).
fact(1,2).
loop(0,_,RV,RV) :- !.
loop(I, Goal, Acc, RV) :- I > 0, NI is I - 1, call(Goal), Goal =.. Lst, last(Lst,Item), writeln(Item), loop(NI, Goal, [Item|Acc], RV).
Как видите, это работает в общем случае:
?- loop(3,fact(1,R), [], RV).
2
2
2
R = 2,
RV = [2, 2, 2].
И снова останавливаемся на random/3 :
?- loop(3,random(1,10,R), [], RV).
9
false.
Я ожидал, что поведение samidet будет сохраняться только в текущем контексте вызова, а не при рекурсивном вызове? (Кстати, swi-docs говорят, что random/3 — это det, а random_between/3 — semidet. Оба терпят неудачу одинаково).
С другой стороны, если я делаю случайный выбор напрямую, а не через call/1, он работает!!!
Это код, из которого я решил абстрагироваться от «цикла» (играя с ugraph lib):
rand_edges(0, _, _, E, E) :- !.
rand_edges(I, RF, RT, E, RV) :- I > 0, NI is I - 1, random(RF,RT,R1), random(RF,RT,R2), rand_edges(NI, RF, RT, [R1-R2|E], RV).
rand_edges(I, RangeFrom, RangeTo, Edges) :- rand_edges(I, RangeFrom, RangeTo, [], Edges).
rand_edges(I, Edges) :- rand_edges(I, 1, 10, [], Edges).
увидеть, как это работает:
?- rand_edges(5,E).
E = [5-5, 9-7, 2-2, 2-7, 3-5].
Почему random/3 не работает в контексте call/1? Но работает как прямой вызов?
Кстати, я случайно наткнулся на random/3, есть ли другие предикаты, которые будут вести себя как random/3?
Согласно Таку:
loop(0,_,RV,RV) :- !.
loop(I, Goal, Acc, RV) :-
I > 0, NI is I - 1, call(Goal), Goal =.. Lst,
%extract the result of the last call in Item, then substitute the last Var with new un-unified Var
reverse(Lst,[Item|T]), reverse([_NewVar|T], NewLst),
NewGoal =.. NewLst, %build a goal with the new-Var
loop(NI, NewGoal, [Item|Acc], RV).
loop(I, Goal, RV) :- loop(I, Goal, [], RV).
?- loop(5, random(1,10,_R), RV).
_R = 7,
RV = [4, 9, 8, 2, 7].