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

时间:2011-09-11 18:46:49

标签: lambda non-deterministic mercury

当我编译下面的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。但是你传入了一个{{ 1}} lambda。“

我的问题:

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

代码:

main

3 个答案:

答案 0 :(得分:4)

Ben是对的,

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

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

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

答案 1 :(得分:3)

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

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

在您的示例中,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的语法相当不令人满意;它们是如此冗长,以至于我通常最终只为最琐碎的lambdas制作命名函数/谓词。



答案 2 :(得分:2)

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

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