Mercury 不在其中
Mercury nondet in det
在Mercury中,假设你在一个det
谓词中,你想调用一个nondet
谓词,如下所示。如果没有解决方案,您需要 Result = []
;如果有一个或多个,您只需要第一个,例如 Result = [FirstSolution]
。 nondet
谓词可能有无限多个解,所以你不能把它们都枚举出来,取第一个。我最接近的是使用 do_while
并在第一个解决方案之后停止,但 do_while
显然是 cc_multi
并且我不知道如何将其强制转换回 det
上下文,甚至回到 multi
上下文,这样我就可以对其应用 solutions
。
你为什么要这样做?如果你这样做是为了优化一些逻辑代码,这样你就可以减少不必要的搜索,那么一定有更好的方法。也许有求解器类型。
无论如何,这在技术上可行:
:- 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).
并有输出:
number tried: 1
number tried: 2
decided on: 2
still want: 2
在浏览 builtin
模块寻找其他东西时,我遇到了一些非常清晰的 "if you want to use cc_multi in a det context" 语言,这让我找到了这个解决方案:
:- module nondetindet3.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module list, string, int, 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.
:- pred first_number(int::out) is semidet.
first_number(N) :-
promise_equivalent_solutions [N] (
even_numbers(N)
).
main(!IO) :-
( if first_number(N1) then
io.format("decided on: %d\n", [i(N1)], !IO)
else true),
( if first_number(N2) then
io.format("still want: %d\n", [i(N2)], !IO)
else true),
( if promise_equivalent_solutions [N3] (even_numbers(N3), N3 > 2) then
io.format("now want: %d\n", [i(N3)], !IO)
else true).
我相信有这个意思"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."
输出:
number tried: 1
number tried: 2
decided on: 2
number tried: 1
number tried: 2
still want: 2
number tried: 1
number tried: 2
number tried: 3
number tried: 4
now want: 4
在Mercury中,假设你在一个det
谓词中,你想调用一个nondet
谓词,如下所示。如果没有解决方案,您需要 Result = []
;如果有一个或多个,您只需要第一个,例如 Result = [FirstSolution]
。 nondet
谓词可能有无限多个解,所以你不能把它们都枚举出来,取第一个。我最接近的是使用 do_while
并在第一个解决方案之后停止,但 do_while
显然是 cc_multi
并且我不知道如何将其强制转换回 det
上下文,甚至回到 multi
上下文,这样我就可以对其应用 solutions
。
你为什么要这样做?如果你这样做是为了优化一些逻辑代码,这样你就可以减少不必要的搜索,那么一定有更好的方法。也许有求解器类型。
无论如何,这在技术上可行:
:- 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).
并有输出:
number tried: 1
number tried: 2
decided on: 2
still want: 2
在浏览 builtin
模块寻找其他东西时,我遇到了一些非常清晰的 "if you want to use cc_multi in a det context" 语言,这让我找到了这个解决方案:
:- module nondetindet3.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module list, string, int, 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.
:- pred first_number(int::out) is semidet.
first_number(N) :-
promise_equivalent_solutions [N] (
even_numbers(N)
).
main(!IO) :-
( if first_number(N1) then
io.format("decided on: %d\n", [i(N1)], !IO)
else true),
( if first_number(N2) then
io.format("still want: %d\n", [i(N2)], !IO)
else true),
( if promise_equivalent_solutions [N3] (even_numbers(N3), N3 > 2) then
io.format("now want: %d\n", [i(N3)], !IO)
else true).
我相信有这个意思"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."
输出:
number tried: 1
number tried: 2
decided on: 2
number tried: 1
number tried: 2
still want: 2
number tried: 1
number tried: 2
number tried: 3
number tried: 4
now want: 4