简体   繁体   English

Det中的汞含量

[英]Mercury nondet in det

In Mercury, suppose you're in a det predicate, and you want to call a nondet predicate, as follows. 在Mercury中,假设您处于det谓词中,并且想要按以下方式调用nondet谓词。 If there are no solutions, you want Result = [] ; 如果没有解决方案,则需要Result = [] ; if there's one or more, you just want the first one like Result = [FirstSolution] . 如果有一个或多个, Result = [FirstSolution]想要第一个,例如Result = [FirstSolution] The nondet predicate may have an infinite number of solutions, so you can't enumerate them all and take the first one. nondet谓词可能具有无限数量的解决方案,因此您无法一一列举所有解决方案并采用第一个解决方案。 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. 我最接近的是使用do_while并在第一个解决方案后停下来,但是do_while显然是cc_multi ,我不知道如何将其强制返回到det上下文,甚至返回到multi上下文,因此我可以申请solutions

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 builtin module 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: 在通过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).

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." 我相信这里的意思是“嘿,不需要继续寻找even_numbers / 1个解决方案,因为所有其他解决方案都不会比您得到的第一个更好。”

Output: 输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM