[mercury-users] [SOLVED] Understanding why a predicate using try/2 is multi (instead of cc_multi)

Andrew Ross andrew at bubblehelicopter.com
Thu Oct 20 12:33:02 AEDT 2011


Hi Ian, thanks for the solution and a clear explanation.

On 20/10/11 9:40 AM, Ian MacLarty wrote:

> On Wed, Oct 19, 2011 at 5:35 PM, Andrew Ross
> <andrew at bubblehelicopter.com> wrote:
>> Hi all, I'm hoping someone here and can help me understand why my mmc infers
>> that my predicate is multi instead of cc_multi. I've tried compiling with
>> --debug-det but the only extra output I got was comments of the form:
>>
>>  Inferred new detism det for predicate`test_do_overflow_safe.run_test'/3 mode 0
>>  Inference pass complete
>>  Inferred old detism det for predicate`test_do_overflow_safe.run_test'/3 mode 0
>>  Inference pass complete
>>  Inferred new detism det for predicate`test_do_overflow_safe.main'/2 mode 0
>>
>> I'm writing unit tests and want to catch exceptions so I can run multiple
>> (related) tests sequentially within a single executable. Test case predicates
>> are passed to a wrapper predicate that is responsible for calling them and
>> catching exceptions.
>>
>> Here is a dummy test function and an implementation of run_test that silently
>> swallows the exception:
>>
>> :- pred main(io::di, io::uo) is det.
>>
>> main(!IO) :-
>>    Test1 = ((pred(N::out) is det) :- N = 0),
>>    run_test(Test1, !IO).
>>
>> :- pred run_test(pred(T), io, io) is det.
>> :- mode run_test(in(pred(out) is det), di, uo).
>>
>> run_test(TestPred, !IO) :-
>>    try(TestPred, _Result).
>>
>> This compiles and runs correctly. By adding a trace goal to Test1 you can see
>> that it is being executed.
>>
>> As soon as I try to do something with the result of try/2 (such as printing it
>> with io.write), mmc infers that run_test is multi:
>>
>>  In `main'(di, uo):
>>   error: determinism declaration not satisfied.
>>   Declared `det', inferred `multi'.
>>   call to `test_do_overflow_safe.run_test'(di(/*
>>   unique */(pred((free >> ground)) is det)), di,
>>   uo) can succeed more than once.
>>  In clause for `main(di, uo)':
>>   mode error: argument 2 did not get sufficiently
>>   instantiated.
>>   Final instantiatedness of `STATE_VARIABLE_IO'
>>   was `mostly_unique',
>>   expected final instantiatedness was `unique'.
>>  In `run_test'(di(/* unique */(pred((free >>
>>   ground)) is det)), di, uo):
>>   error: invalid determinism for a predicate with
>>   I/O state arguments.
>>   Valid determinisms are det, cc_multi and
>>   erroneous.
>>  Inferred :- pred run_test((pred T), io.state,
>>   io.state).
>>  Inferred :- mode run_test(di(/* unique
>>   */(pred((free >> ground)) is det)), di, uo) is
>>   multi.
>>  Error: call to predicate `exception.try'/2 with
>>   determinism `cc_multi' occurs in a context which
>>   requires all solutions.
>>
>> Wrapping try/2 in promise_equivalent_solutions allows the compilation to
>> succeed, but I'm wary of using that without fully understanding why run_test is
>> being treated as multi.
>>
>> I read the thread at
>> http://www.mercury.csse.unimelb.edu.au/mailing-lists/mercury-users/mercury-users.201005/0011.html
>> but that deals with why you need to explicitly convert cc_multi to det with
>> promise_equivalent_solutions, where as I would be happy for cc_multi to bubble
>> up to main.
> 
> In your example above, you've declared main as det.  You can declare
> it as cc_multi if you want to avoid the promise_equivalent_solutions
> in run_test.

> I'm not sure exactly why the system infers run_test to be multi
> instead of cc_multi if you omit the mode declarations.  I'd guess it's
> probably just a weakness in the mode inference.  Usually you're better
> off adding explicit mode and type declarations to all your predicates.

I _thought_ I'd tried an explicit mode and type declaration for run_test
(especially since that's how I normally write Mercury code), falling back to
inference only because of an error message I was having trouble understanding:

 In `run_test'(in((pred((free >> ground)) is det)), di,
   uo):
   error: invalid determinism for a predicate with I/O
   state arguments.
   Valid determinisms are det, cc_multi and erroneous.
 Error: call to predicate `exception.try'/2 with
   determinism `cc_multi' occurs in a context which
   requires all solutions.

After several re-readings of my code, I finally noticed the problem with this:

:- pred run_test(pred(T), io, io) is cc_multi.
:- mode run_test(in(pred(out) is det), di, uo).

Once I moved the determinism declaration to the mode declaration everything
worked perfectly. The compiler was telling me problem all along, but I just
wasn't listening! I'd love to blame it on the heat, but yesterday wasn't hot
enough so I'll have to admit that it was a rookie mistake :-)

Thanks again,

Andrew
--------------------------------------------------------------------------
mercury-users mailing list
Post messages to:       mercury-users at csse.unimelb.edu.au
Administrative Queries: owner-mercury-users at csse.unimelb.edu.au
Subscriptions:          mercury-users-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the users mailing list