See also
forall/2 as a better alternative to the failure-driven loop
Alternative to the failure-driven loop
As long as the compiler can do tail-call optimization (hopefully) is of course recursion:
read_terms :- read(Term),process_and_read(Term). process_and_read(end_of_file) :- !. process_and_read(T) :- process(T),read(TN), !, process_and_read(TN).
Far cleaner.
Limiting repeats
I you do not want +∞ of redoes, but just K of them,
you can use between/3 (is can be found under integer arithmetic) or use predicates from library(solution_sequences). There is also findnsols/4
?- between(1,4,X), format("Hello ~d!\n",[X]), fail. Hello 1! Hello 2! Hello 3! Hello 4! false.
Alternatively:
using library(solution_sequences), generate only two solutions from the infinite sequence of list templates that will be generated:
?- limit(3,length(Length,List)). Length = [], List = 0 ; Length = [_18068], List = 1 ; Length = [_18068, _19116], List = 2.
So, programmatically:
?- bagof([Length,List],limit(3,length(Length,List)),Bag). Bag = [[[], 0], [[_20374], 1], [[_20344, _20350], 2]].
Or you can use call_nth/2 from the same library to do the following:
?- findall([Length,List],(call_nth(length(Length,List),N),(N>3->!,fail;true)),R). R = [[[], 0], [[_12141708], 1], [[_12141678, _12141684], 2]].
Special
Another thing good to know (not only in the context of repeat/0) is how to perform a predicate call only on "redo"
do(X) :- repeat, (true ; (format("Going to hit repeat/0 coming from the 'right' with K = ~q\n",[K]),fail) ), format("Now trying something, K = ~q\n",[K]) , random(0.0,1.0,X) , format("Obtained ~q\n",[X]) , (true ; (format("NOPE! ~q doesn't cut it\n",[X]),fail) ), X < 0.2, format("Done!\n"), !.