Goal determinism when less than 2 solutions

It seems common to have a predicate that produces one solution, leaving behind some choicepoints to check which then never result in a second solution, thus producing an unwanted “there may be more solutions… oh there isn’t” teaser.

These wrappers should help reduce that, with the disadvantage that the Goal is called twice.

% For predicates intended to never succeed twice
succeeds_once(Goal) :-
    % Ensure there are not 2 solutions or more
    \+ call_nth(Goal, 2),

% For predicates which can have many solutions, but usually 1
fewer_choicepoints(Goal) :-
    (   \+ call_nth(Goal, 2)
        % Less than 2 solutions, so cut after it
    ->  Goal, !
    ;   Goal

These will reduce unwanted choicepoints, when there is 1 solution, whilst being convenient to use:

?- member(X, [a]) ; false.
X = a ;
false. % An example of an unwanted choicepoint

?- succeeds_once(member(X, [a]) ; false).
X = a. % No unwanted choicepoint

?- succeeds_once(member(X, [a]) ; true).
false. % Bypasses presenting the first solution of the 2 solutions

?- fewer_choicepoints(member(X, [a]) ; false).
X = a. % No unwanted choicepoint

?- fewer_choicepoints(member(X, [a, b]) ; false).
X = a ;
X = b ;
false. % Redundant choicepoint - no worse than usual

Perhaps there are better, succinct names for these predicates.

1 Like

A request for a solution set could apply here. How about findall/3? It returns only one answer.

  ?- findall(X, member(X,[a]),All).
   All = [a].

   ?- findall(X, member(X,[]),All).
   All = [].

   ?- findall(X, member(X,[a,b,c]),All).
   All = [a, b, c].

Dealing with just Goal, rather than having to also manually identify the variables involved, is more convenient.

A list of variables can be more difficult to visually digest, depending on their complexity (e.g. compound terms), especially if some of the variable components are themselves lists.

1 Like