[英]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.