This was my initial bump-up with the notion of determinacy in Prolog : Why does Prolog does not backtrack on comparison?
I also found this discussion interesting : Has the notion of 'semidet' in Prolog settled?
I wanted to implement more general loop construct (that behave like findall) : (BTW: findall source seem weird, cant understand what this '$....' is all about).
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).
As you can see it works in the general case :
?- loop(3,fact(1,R), [], RV).
2
2
2
R = 2,
RV = [2, 2, 2].
And again balks-up on random/3 :
?- loop(3,random(1,10,R), [], RV).
9
false.
I expected samidet behavior to hold only in the current call-context not when called recursively ? (BTW, swi-docs say that random/3 is det and random_between/3 is semidet. Both fail in the same way).
On the other hand if I do random directly rather than via call/1 it works !!!
This is the code from which I decided to abstract 'loop' (playing with 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).
see it working :
?- rand_edges(5,E).
E = [5-5, 9-7, 2-2, 2-7, 3-5].
Why random/3 doesn't work in call/1 context ? But works as direct call ?
BTW, I just happen to stumble upon random/3, is there other predicates that will behave like random/3 ?
As per Taku :
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].
It's because once R
of random(1,10,R)
becomes ground(bound to a value),
no longer R cannot be changed.
At recursion call of loop(NI, Goal, [Item|Acc], RV)
part ,
Goal
is patternmatched to random(1,10,9)
actually and 9
cannnot be changed.
you should make this 9
change to free variable.
this code will work as you intended.
loop(0,_,RV,RV) :- !.
loop(I, Goal, Acc, RV) :-
I > 0,
NI is I - 1,
call(Goal),
Goal =.. Lst,
last(Lst,Item),
writeln(Item),
nth1(1, Lst, First),
nth1(2,Lst,Second),
nth1(3,Lst,Third),
Goal2 =.. [First,Second,Third,NewRand],
loop(NI, Goal2, [Item|Acc], RV).
?- loop(5,random(1,10,R),[],RV).
7
9
2
4
2
R = 7,
RV = [2, 4, 2, 9, 7].