在Mercury中,为什么我不能在函数应用程序中使用状态变量?

时间:2014-04-19 23:13:31

标签: mercury

在描述状态变量时,Mercury reference manual说:" !X可能不会在函数应用程序中显示为参数,因为这对于状态变量的通常解释是没有意义的和功能" (第14页)。我想更好地理解这种推理:状态变量和函数是什么让这种组合无意义?

我的一些困惑来自下面的代码,我可以使用!.X, !:X形式的状态变量,但不能使用!X形式。如果我可以使用前者,为什么不使用前者?

此代码编译并按预期运行:

% Choose values, A and B, from the list of values, subject to certain restrictions
:- pred pick_a_b(int, int, list(int), list(int)).
:- mode pick_a_b(out, out, in,        out) is nondet.
pick_a_b(A, B, !Values) :-
    A = pick(!.Values, !:Values),
    B = pick(!.Values, !:Values),
    A \= 3, A > 2, B > 2, B \= 4.

% Choose any item from the input list; pass all the un-chosen items back to the caller.
:- func pick(list(int), list(int)) = int.
:- mode pick(in,        out)       = out is nondet.
pick([X | Xs], Xs)      = X.
pick([X | Xs], [X | Zs]) = pick(Xs, Zs).

main(!IO) :-
    if 
        Values = [1, 2, 3, 4, 5],
        pick_a_b(A, B, Values, _)
    then
        io.format("A = %i\n", [i(A)], !IO),
        io.format("B = %i\n", [i(B)], !IO)
    else
        io.format("Something went wrong\n", [], !IO).

但更改pick_a_b的前两行会导致编译错误。

pick_a_b(A, B, !Values) :-
    A = pick(!Values),
    B = pick(!Values),
    A \= 3, A > 2, B > 2, B \= 4.

2 个答案:

答案 0 :(得分:3)

你的“功能”选择有一个奇怪的模式,(in,out)= out。这是非常不寻常的,这就是为什么!:Values语法适用于您的第一个示例。它通常不会因为函数通常具有模式(in,in,...,in)= out。

参考手册是正确的说!!X语法在函数调用中没有意义,我也相信你使用!:值和你的函数模式也没有意义。是的,你的代码是合法的,编译器接受它并可以编译它,但是我不知道为什么有人会在这里使用函数而不是谓词。这样做可能会让人们在将来阅读您的代码时感到困惑。

答案 1 :(得分:1)

状态变量的通常解释是,其中一个是输入,另一个是输出,函数的通常解释是所有参数都是输入,返回值是输出。参考手册指出,鉴于这些解释,使用状态变量作为参数是没有意义的。

推理可能总结为:只是因为你可以允许程序员写一些东西,并不意味着你应该