[mercury-users] Disable or warn for implicit modes?

Julien Fischer juliensf at csse.unimelb.edu.au
Mon Feb 27 13:12:41 AEDT 2012


On Sun, 26 Feb 2012, Jeff Thompson wrote:

> Thanks for the detailed reply on how the compiler selects the mode.  I ran 
> across another case where the code with running slower than I expected.  Here 
> is the example:
> :- pred test(bool::in, list(int)::out, list(int)::out, list(int)::in) is 
> nondet.
> test(SetEnd, Start, End, List) :-
>  (if SetEnd = yes then
>    End = [1]
>  else
>    true),
>  append(Start, End, List).
> I (naively) expected End to be ground if SetEnd is yes, so that append would 
> be called with the more efficient semidet mode (out, in, in).

The else branch of that if-then-else does not make End ground.  The
compiler cannot place a call to append(out, in, in) at the end of the
if-then-else becase doing the resulting call would not be mode correct
in the case where SetEnd = no.  (Note that a single mode of append is
chosen at compile time, the implementation does *not* dynamically select
one based upon the insantiatedness of the arguments, i.e. the selected
mode needs to work for all possible execution paths through the

> the compiler re-orders the code to call append with mode(out, out, in) to 
> return all search results, and only test End = [1] on each return.

That's correct.  The predicate declaration for test/4 says that End has
mode out, that means that End must be produced by all (non-erroneous)
paths through the clause.  Reording the clause so that that it becomes:

    test(SetEnd, Start, End, List) :-
      append(Start, End, List),
      ( if SetEnd = yes then
         End = [1]

is the only way to ensure this condition.

> To get the compiler to use the efficient semidet mode, I had to
> explicitly change the code to:
> test(SetEnd, Start, End, List) :-
>  (if SetEnd = yes then
>    End = [1],
>    append(Start, End, List)
>  else
>    append(Start, End, List)).
> Is there some trick to avoid having to remember to put the same code for 
> append in two places?

Arguably they are not the same code for append, one first is in the
mode (out, in, in) while the second is (out, out, in).

The "trick" here I suspect, is to understand that for disjunctive goals
in Mercury (disjuntions, switches and if-then-elses), any non-local
variables must have the same inst at the end of every branch.  (That
is not the case with End above, which is ground at the end of the then
branch and free at the end of the else branch.)

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