Mercury中的ADT属性

时间:2010-07-29 06:31:01

标签: logic declarative mercury

我徘徊为什么水星(10.04)无法推断下一个片段的确定性:

:- pred load_freqs(int::in, io.res(list(float))::out, io::di, io::uo) is det.
load_freqs(CPU, ResFreqs, !IO):-
    open_input(cpu_fn(CPU, "available_frequencies"), ResStream, !IO),
    (ResStream = io.ok(Stream) ->
        ResFreqs = io.ok([])
    ;ResStream = io.error(Err),
        ResFreqs = io.error(Err)
    ).

它抱怨道:

cpugear.m:075: In `load_freqs'(in, out, di, uo):
cpugear.m:075:   error: determinism declaration not satisfied.
cpugear.m:075:   Declared `det', inferred `semidet'.
cpugear.m:080:   Unification of `ResStream' and `io.error(Err)' can fail.
cpugear.m:076: In clause for predicate `cpugear.load_freqs'/4:
cpugear.m:076:   warning: variable `CPU' occurs only once in this scope.
cpugear.m:078: In clause for predicate `cpugear.load_freqs'/4:
cpugear.m:078:   warning: variable `Stream' occurs only once in this scope.

io.res只有io.ok/1io.error/1 下一段代码汇编得很好:

:- pred read_freqs(io.res(io.input_stream)::in, io.res(list(float))::out, io::di, io::uo) is det.
read_freqs(io.ok(Stream), io.ok([]), IO, IO).
read_freqs(io.error(Err), io.error(Err), IO, IO).

更新#1 : 即使对于:

,它也可以决定
:- pred read_freqs(bool::in, io.res(io.input_stream)::in, io.res(list(float))::out, io::di, io::uo) is det.
read_freqs(no, ResStream, io.ok([]), IO, IO):- ResStream = io.ok(_).
read_freqs(F, io.ok(_), io.ok([]), IO, IO):- F = yes.
read_freqs(yes, io.error(Err), io.error(Err), IO, IO).
read_freqs(F, ResStream, io.error(Err), IO, IO):- ResStream = io.error(Err), F = no.

3 个答案:

答案 0 :(得分:2)

我对有条件的确定性的Mercury规则的阅读(下文)是,为了将其视为确定性的,您应该将->替换为,

来自Mercury参考手册:

  

如果条件为if-then-else   不能失败,if-then-else是   相当于。的结合   条件和“然后”部分,及其   相应地计算确定性。   否则,if-then-else可能会失败   “然后”部分或“其他”   部分可能会失败。

答案 1 :(得分:2)

至于'为什么'。让我们用if-then-else:

查看原始代码
(ResStream = io.ok(Stream) ->
    ResFreqs = io.ok([])
;ResStream = io.error(Err),
    ResFreqs = io.error(Err)
).

如果条件失败,则else案例中的第一个合并是semidet测试。编译器不知道它必须成功(这可以通过知道该条件失败来推断)。换句话说,编译器不够智能。

也就是说,发现这个问题的情况很少见,因为通常条件更复杂并且不允许进行这种推断,因此编译器不够聪明以确定正确的确定性并不重要

建议尽可能使用开关进行编程(例如本例),它可以防止当前问题,并有助于确保您已经涵盖了所有可能的ResStream案例。例如,如果将来io.error被重新考虑并且可能是io.error_file_not_found或io.error_disk_full等,编译器将指示程序员修复他们的开关,因为它现在不完整。

答案 2 :(得分:1)

好的,它可以推断出:

:- pred load_freqs(int::in, io.res(list(float))::out, io::di, io::uo) is det.
load_freqs(CPU, ResFreqs, !IO):-
    open_input(cpu_fn(0, "available_frequencies"), ResStream, !IO),
    (ResStream = io.ok(Stream),
        ResFreqs = io.ok([])
    ;ResStream = io.error(Err),
        ResFreqs = io.error(Err)
    ).

但为什么“if-then-else”结构引入了semidet?