Lambda Mercury:如何声明高阶数据类型的决定论?
当我编译下面的Mercury代码时,我从编译器中得到以下错误:Lambda Mercury:如何声明高阶数据类型的决定论?,lambda,non-deterministic,mercury,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)
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\u case
时,您没有指定确定性,因此我假设您的意思是det
。但随后您传入了一个semidet
lambda。”
我的问题是:
- 声明类型决定论的语法是什么?我尝试过的猜测都导致了语法错误
- 有人能解释一下
部分/*惟一的*/
测试用例的实例化意味着什么吗?这是否会导致给定实例化和预期实例化之间的不匹配
- 在
中声明lambda是否有一种不那么冗长的方法?我对lambda的声明和lambda中的代码一样多main
% (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).
这也花了我一段时间来掌握窍门 问题是高阶项的模式不是其类型的一部分。因此,没有语法来声明类型的决定论。模式中带有高阶项的决定论 在您的示例中,
assert_equals
的第一个参数具有typetest_case(T)
,但在中具有mode。这意味着函数为semidet
的事实将丢失。如果您传递的函数是det
,我不确定它是否能够正确编译或运行;即使在这种情况下,模式也不应该是
中的
下面是一个例子:
:- 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\u transformer
的第一个参数的类型仅表示它是一个高阶函数,它接受一个参数并返回相同类型的结果。模式声明实际上表明函数参数具有模式in
,函数结果具有模式out
,其决定性为det
我相信错误消息的/*unique*/
位表示编译器认为它是唯一的值。我不确定这是否是一个问题,因为除了通常的io
状态之外,您在任何地方都没有使用独特的模式
至于lambda语法,我不认为你能做得更好。我发现Mercury中lambdas的语法相当不令人满意;它们太冗长了,以至于我通常只为所有的lambda(除了最简单的lambda)创建命名函数/谓词
本是对的
我想补充一点,Mercury默认假定函数是确定性的(函数应该是确定性的,这是明智的)。对于必须声明决定论的谓词,情况并非如此。这使得使用确定性函数进行高阶编程比使用任何其他函数或谓词更容易,这仅仅是因为样本较少
因此,您可以使lambda表达式更加简洁。还可以通过用主体替换head中的变量S,将lambda表达式的主体移动到head中
apply_transformer((func(S0) = "Hello " ++ S0),
"World", Msg),
为了回答第二个问题,错误消息中的/*unique*/
引用了调用assert_equals
的第一个参数,这是您刚才构造的lambda术语。这是唯一使用术语的地方,因此在调用时对它的引用是唯一的
唯一inst与地面inst匹配(但反之亦然),因此在这种情况下,唯一性不会导致不匹配。问题在于决定论。谢谢,本。这个解释是有道理的(它解决了我的问题!)@Evan:我忘了在我的答案中添加,也可以为高阶项的复杂模式创建模式别名。我曾经为一个模块做过一次,该模块有几十个谓词,它们采用相同类型的高阶参数;我在模块顶部声明了一个类型和一个模式,并在整个模块中使用了它们。@Evan:嘿,你想看一下吗?与这篇文章无关,只是为了吸引Evan的注意