0

在 Mercury 中,假设您在一个det谓词中,并且您想调用一个nondet谓词,如下所示。如果没有解决方案,你想要Result = [];如果有一个或多个,你只想要第一个喜欢Result = [FirstSolution]. 谓词可能有无限数量的nondet解,因此您无法将它们全部枚举并取第一个。我最接近的是使用do_while并在第一个解决方案之后停止,但do_while显然cc_multi我不知道如何将它强制回到det上下文中,甚至回到multi上下文中以便我可以应用solutions它。

4

2 回答 2

1

你到底为什么要这样做?如果您这样做是为了优化一些逻辑代码,从而减少不必要的搜索,那么一定有更好的方法。也许有求解器类型的东西。

无论如何,这在技术上是有效的:

:- 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
于 2019-07-20T21:57:36.270 回答
1

在通过模块扫描builtin其他内容时,我遇到了一些非常明确的“如果你想在 det 上下文中使用 cc_multi”语言,这导致我找到了这个解决方案:

:- 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).

我相信这里的意思是“嘿,不需要继续搜索 even_numbers/1 解决方案,因为所有其他解决方案都不会比你得到的第一个解决方案更好。”

输出:

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
于 2019-07-24T12:51:55.313 回答