It took me a while to hang too.
The problem is that a higher order mode is not part of its type. Thus, there is no syntax for declaring type determinism. Higher-order determinism is tolerated in mode.
In your example, the first argument to assert_equals is of type test_case(T) , but has a mode of in . This means that the semidet function is lost. I'm not sure if it will really compile or run correctly if the function you pass was det ; even in this case, the mode really should not be in .
Here is an example:
:- 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).
As you can see, the type of the first argument to apply_transformer only says that this higher-order function takes one argument and returns a result of the same type. This is a mode declaration, which actually says that the parameter of the function has the mode in , and the result of the function has the mode out , and its determinism is det .
I believe that the /*unique */ bit of the error message says that the compiler considers it unique. I am not sure if this is a problem or not, since you are not using unique modes anywhere other than the normal io state.
Regarding lambda syntax, I don't think you can do anything for the better, unfortunately. I find the lambda syntax in Mercury to be quite unsatisfactory; they are so verbose that I usually end up doing named functions / predicates instead of all but the most trivial lambdas.