

Definitely prefer once/1 over ->/2. It makes the intent clear and, unlike ->/2, is actually readable.
Example
An example of a predicate which sometimes fails and sometimes succeeds with 1 or more solutions: 50 tries to generate a random number from [1..100] which must be in [3,4,5]:
?- (between(1,50,X)
,random_between(1,100,R)
,member(R,[3,4,5])
).
X = 15,
R = 3 ;
false.
Using once/1 on this:
?- once((between(1,50,X),random_between(1,100,R),member(R,[3,4,5]))). X = 17, R = 3. ?- once((between(1,50,X),random_between(1,100,R),member(R,[3,4,5]))). X = R, R = 5. ?- once((between(1,50,X),random_between(1,100,R),member(R,[3,4,5]))). X = 49, R = 5. ?- once((between(1,50,X),random_between(1,100,R),member(R,[3,4,5]))). false.
Where is twice/1 ?
If there is a once/1
, there should probably be a twice/1
etc.
And there is: limit/2 from library(solution_sequences)