繁体   English   中英

Mercury:如何声明高阶数据类型的确定性?

[英]Mercury: How to declare determinism of a higher-order data type?

当我编译下面的Mercury代码时,我从编译器中得到这个错误:

In clause for `main(di, uo)':
  in argument 1 of call to predicate
  `test_with_anonymous_functions.assert_equals'/5:
  mode error: variable `V_15' has
  instantiatedness `/* unique */((func) =
  (free >> ground) is semidet)',
  expected instantiatedness was `((func) =
  (free >> ground) is det)'.

我认为编译器所说的是“当你声明类型test_case ,你没有指定一个确定性,所以我认为你的意思是det 。但是你传入了一个semidet lambda。”

我的问题:

  • 声明类型的确定性的语法是什么? 我尝试过的猜测都导致了语法错误。
  • 有人可以解释一下TestCase实例化的/* unique */部分是什么意思吗? 这会导致给定和预期的实例化之间的不匹配吗?
  • 是否有一种不那么冗长的方式来声明lambda main 我在lambda中编写了关于lambda的声明。

编码:

% (Boilerplate statements at the top are omitted.)

% Return the nth item of a list
:- func nth(list(T), int) = T.
:- mode nth(in,      in)  = out is semidet.
nth([Hd | Tl], N) = (if N = 0 then Hd else nth(Tl, N - 1)).

% Unit testing: Execute TestCase to get the 
% actual value. Print a message if (a) the lambda fails
% or (b) the actual value isn't the expected value.
:- type test_case(T) == ((func) = T).
:- pred assert_equals(test_case(T), T,  string, io.state, io.state).
:- mode assert_equals(in,           in, in,     di,       uo) is det.
assert_equals(TestCase, Expected, Message, !IO) :-
    if   Actual = apply(TestCase), Actual = Expected
    then true % test passed. do nothing.
    else io.format("Fail:\t%s\n", [s(Message)], !IO).

main(!IO) :-
    List = [1, 2, 3, 4],
    assert_equals( ((func) = (nth(List, 0)::out) is semidet),
                 1, "Nth", !IO).

本是对的,

我想补充一点,Mercury假定函数默认是确定性的(函数应该是确定性的,这是明智的)。 对于必须声明确定性的谓词,情况并非如此。 这使得使用确定性函数进行高阶编程比使用任何其他函数或谓词更容易,因为它的样板更少。

因此,您可以使lambda表达式更简洁。 您还可以通过用主体替换头部中的变量S,将lambda表达式的主体移动到头部。

apply_transformer((func(S0) = "Hello " ++ S0),
                  "World", Msg),

这花了我一点时间才得到了好处。

问题是高阶项的模式不是其类型的一部分。 因此,没有声明声明类型的确定性的语法。 高阶项的确定性在模式中进行。

在示例中,第一个参数assert_equals具有类型test_case(T)但具有模式in 这意味着函数是semidet的事实会丢失。 如果您传递的函数是det ,我不确定它是否会实际编译或正确运行; 即使在那种情况下,模式真的不应该in

这是一个例子:

:- pred apply_transformer(func(T) = T, T, T).
:- mode apply_transformer(func(in) = out is det, in, out).
apply_transformer(F, X0, X) :-
    X = F(X0).

main(!IO) :-
    apply_transformer((func(S0) = S is det :- S = "Hello " ++ S0),
                      "World", Msg),
    print(Msg, !IO),
    nl(!IO).

正如您所看到的, apply_transformer的第一个参数的类型仅表示它是一个高阶函数,它接受一个参数并返回相同类型的结果。 它是模式声明,实际上说函数参数有模式in ,函数结果有模式out ,它的确定性是det

我相信错误消息的/*unique */位表示编译器认为它是唯一值。 我不确定这是否是一个问题,因为除了通常的io状态之外,你没有使用任何其他模式。

至于lambda语法,我不认为你可以做得更好。 我发现水星中lambda的语法相当不令人满意; 他们是如此冗长,以至于我通常最终只是为了除了最琐碎的lambda之外的所有人而制作命名函数/谓词。



要回答第二个问题,错误消息中的/* unique */是指对assert_equals的调用的第一个参数,这是你刚刚构造的lambda术语。 这是该术语使用的唯一位置,因此对它的引用在调用时是唯一的。

一个独特的inst匹配地面inst(但反之亦然),因此在这种情况下,唯一性不会导致不匹配。 问题是决定论。

暂无
暂无

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

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