Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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:

  • What's the syntax for declaring the determinism of a type? The guesses I've tried have all resulted in syntax errors.
  • Can someone explain what the /* unique */ part of TestCase's instantiatedness means? Will that cause a mismatch, between the given & expected instantiatedness?
  • Is there a less verbose way of declaring the lambda in 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).
like image 614
Evan Avatar asked Jan 19 '23 18:01

Evan


1 Answers

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),
like image 56
Paul Bone Avatar answered Jan 31 '23 08:01

Paul Bone