[mercury-users] Mode checking if-then-else vs less readable switch

Andrew Ross andrew at bubblehelicopter.com
Thu Aug 25 11:45:03 AEST 2011


Hi all, I'm wondering if I've hit a limitation in the mode checker of
the Mercury compiler, or if I just need more experienced Mercury users
to point me in the right direction :-)

A simplified example:

:- import_module int.
:- import_module string.

:- type const_or_var
    --->    const(int)
    ;       var(string).

:- inst var
    --->    var(ground).

:- inst const
    --->    const(ground).

:- func plus(const_or_var, const_or_var) = const_or_var.
:- mode plus(in(const), in(const)) = out(const) is det.
:- mode plus(in(var), in) = out(var) is det.
:- mode plus(in, in(var)) = out(var) is det.

My intention with these modes is to allow mmc to infer that callers are
det when they do things like:

var(NewVarName) = plus(var("V"), const(0))

With the mode "plus(in, in) = out is det" mmc thinks the unification can
fail. If we want the caller to be det we need to use the above-mentioned
modes or make the calling code be:

NewVar = plus(var("V"), const(0)),
(
    NewVar = var(NewVarName)
;
    NewVar = const(_),
    unexpected($module, $pred, "var + const should equal var")
)

This extra code can be optimized away, but it still annoys me that
anyone reading it is given the false impression that a run-time error
could occur here. Perhaps I'm overreacting, but I'm happier with the
one-line version of the calling code and the extra modes for plus.

Now, a concise implementation of plus is:

plus(A, B) = Z :-
    ( if
        A = const(IntA),
        B = const(IntB)
    then
        Z = const(IntA + IntB)
    else
        Z = var("A + B")
    ).

but this fails mode checking:

 In clause for `plus(in((itest.const)), in((itest.const))) =
   out((itest.const))':
   mode error: argument 3 had the wrong instantiatedness.
   Final instantiatedness of `Z' was `unique(itest.const(unique) ;
   itest.var(unique("A + B")))',
   expected final instantiatedness was
  `bound(itest.const(ground))'.

The following implementation passes mode checking, but (in my opinion)
it's less readable than the previous version. It's certainly more
error-prone, since it has duplicated code.

plus(A, B) = Z :-
    (
        A = const(IntA),
        (
            B = const(IntB),
            Z = const(IntA + IntB)
        ;
            B = var(_),
            Z = var("A + B")
        )
    ;
        A = var(_),
        Z = var("A + B")
    ).

Should the mode checker be able to infer that the if-then-else version
of plus satisfies the declared modes?

Cheers

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