In Mercury, suppose you're in a det predicate, and you want to call a nondet predicate, as follows. If there are no solutions, you want Result = []; if there's one or more, you just want the first one like Result = [FirstSolution]. The nondet predicate may have an infinite number of solutions, so you can't enumerate them all and take the first one. The closest I've come is to use do_while and just stop after the first solution, but do_while is apparently cc_multi and I don't know how to coerce it back into a det context, or even back into a multi context so I can apply solutions to it.
Mercury nondet in det
151 Views Asked by Erhannis At
2
There are 2 best solutions below
1
On
Why exactly do you want to do this? If you're doing it to optimize some logical code, so that you do less unnecessary searching, there must be a better way. Something with solver types perhaps.
Anyway, this technically works:
:- module nondetindet.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module list, string, int, bool, solutions.
:- pred numbers(int::out) is multi.
numbers(N) :-
( N = 1; N = 2; N = 3; N = 4 ),
trace [io(!IO)] (io.format("number tried: %d\n", [i(N)], !IO)).
:- pred even_numbers(int::out) is nondet.
even_numbers(N) :-
numbers(N),
N rem 2 = 0.
:- initialise(set_number/0).
:- mutable(number, int, 0, ground, [untrailed]).
:- impure pred set_number is cc_multi.
set_number :-
do_while(even_numbers, (pred(N1::in, no::out, _::in, N1::out) is det), 0, N),
impure set_number(N).
:- func first_number = int.
:- pragma promise_pure(first_number/0).
first_number = N :- semipure get_number(N).
main(!IO) :-
io.format("decided on: %d\n", [i(first_number)], !IO),
io.format("still want: %d\n", [i(first_number)], !IO).
And has output:
number tried: 1
number tried: 2
decided on: 2
still want: 2
While scanning through the
builtinmodule for something else, I came across very some clear "if you want to use cc_multi in a det context" language that led me to this solution:I believe the meaning there is "hey, no need to keep searching for even_numbers/1 solutions, 'cause all those other solutions are going to be no better than the first one you get."
Output: