When I compile the Mercury code below, I get this error from the compiler:
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)'.
I think what the compiler is saying is "When you declared the type test_case
, you didn't specify a determinism, so I assumed you meant det
. But then you passed in a semidet
lambda."
My questions:
/* unique */
part of TestCase
's instantiatedness means? Will that cause a mismatch, between the given & expected instantiatedness?main
? I have as much declaration about the lambda as I do code inside the lambda.The code:
% (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).
Ben is right,
I'd like to add that Mercury assumes that functions are deterministic by default (it's sensible that functions ought to be deterministic). This is not true for predicates in which the determinism must be declared. This makes it easier to do higher order programming with deterministic functions than any other function or predicate, simply because there's less boilerplate.
Because of this, you are able to make your lambda expression a little bit more concise. You can also move the body of the lambda expression into the head by substituting the variable S in the head with the body.
apply_transformer((func(S0) = "Hello " ++ S0),
"World", Msg),
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With