If I remember right --as a special case-- there is also a guaranteed no choicepoint between []
and [_|_]
in the first argument, correct?
Example
just to make it easy for readers of this thread, here are some examples on how to design your clauses:
% Examples using atom, small integer or ftor to discriminate
% without leaving a choice point.
atom_nochp(one, W) :- writeln(one(W)).
atom_nochp(two, W) :- writeln(two(W)).
smallint_nochp(33, W) :- writeln('33'(W)).
smallint_nochp(101, W) :- writeln('101'(W)).
ftor_nochp(onearg(A), W) :- writeln('onearg/1'(A,W)).
ftor_nochp(another_onearg(A), W) :- writeln('another_onearg/1'(A,W)).
ftor_nochp(twoargs(A), W) :- writeln('twoargs/2'(A,W)).
list_nochp([]) :- writeln('empty_list').
list_nochp([_|_]) :- writeln('non empty_list').
test_nochp :-
atom_nochp(one,'no choicepoint!'),
smallint_nochp(33,'no choicepoint!'),
ftor_nochp(another_onearg(1),'no choicepoint!'),
list_nochp([1]).
% These leave choice points, as they don't use the first argument
atom_chp(W, one) :- writeln(one(W)).
atom_chp(W, two) :- writeln(two(W)).
smallint_chp(W, 33) :- writeln('33'(W)).
smallint_chp(W, 101) :- writeln('101'(W)).
ftor_chp(W, onearg(A)) :- writeln('onearg/1'(A,W)).
ftor_chp(W, another_onearg(A)) :- writeln('another_onearg/1'(A,W)).
ftor_chp(W, twoargs(A)) :- writeln('twoargs/2'(A,W)).
list_chp([_]) :- writeln('one_elem_list').
list_chp([_,_|_]) :- writeln('two_or_more_elem_list').
test_chp :-
atom_chp('choicepoint!',one),
once(print_last_choicepoint),
smallint_chp('choicepoint!',33),
once(print_last_choicepoint),
ftor_chp('choicepoint!',another_onearg(1)),
once(print_last_choicepoint),
list_chp([1]),
once(print_last_choicepoint).
Queries:
21 ?- test_nochp.
one(no choicepoint!)
33(no choicepoint!)
another_onearg/1(1,no choicepoint!)
non empty_list
true.
22 ?- test_chp.
one(choicepoint!)
Warning: atom_chp('choicepoint!',one) left a choice point in alternate clause (after success)
Warning: /tmp/t1.pl:25: clause succeeded
Warning: /tmp/t1.pl:26: next candidate clause
Warning: Called from
Warning: [10] test_chp at /tmp/t1.pl:39
33(choicepoint!)
Warning: smallint_chp('choicepoint!',33) left a choice point in alternate clause (after success)
Warning: /tmp/t1.pl:28: clause succeeded
Warning: /tmp/t1.pl:29: next candidate clause
Warning: Called from
Warning: [10] test_chp at /tmp/t1.pl:41
another_onearg/1(1,choicepoint!)
Warning: ftor_chp('choicepoint!',another_onearg(1)) left a choice point in alternate clause (after success)
Warning: /tmp/t1.pl:32: clause succeeded
Warning: /tmp/t1.pl:33: next candidate clause
Warning: Called from
Warning: [10] test_chp at /tmp/t1.pl:43
one_elem_list
Warning: list_chp([1]) left a choice point in alternate clause (after success)
Warning: /tmp/t1.pl:35: clause succeeded
Warning: /tmp/t1.pl:36: next candidate clause
Warning: Called from
Warning: [10] test_chp at /tmp/t1.pl:45
true [...]
You need SWI-Prolog 8.5.4 for print_last_choicepoint/0
. Otherwise just delete it from the source, it is just a convenience so you can see the choicepoints.
Bottom line
- if you want no choicepoints:
- Make the \color{red}\text{first argument} of the clauses \color{red}\text{a different atom, small int or functor}
- for a functor to be different they need to have a different name and/or arity.
- As a special case you don’t get a choice point between
[]
and [_|_]
in the first argument.
EDIT: In the example for twoargs
functor I forgot to add the other arg , left as an exercise