# [mercury-users] Rewriting if-then-else as (CondGoal, ThenGoal; not(CondGoal), ElseGoal)

Peter Ross pro at missioncriticalit.com
Mon Sep 5 12:51:50 AEST 2011

```On Mon, Sep 5, 2011 at 11:45 AM, Daniel Patterson
<lists.mercury at dbp.mm.st> wrote:
>
> Hi,
>
> sorry if this is a really beginner question, but I have an example program (that solves the first of the project euler problems):
>
> :- pred euler1(int::in,int::out) is det.
>
> euler1(N,P) :-
>  Np = N mod 3, Nq = N mod 5,
>  ( if
>      N =< 0
>    then
>      P = 0
>    else
>        (
>          if (Np = 0; Nq = 0)
>          then euler1(N-1,Ps), P = N + Ps
>          else euler1(N-1,P)
>        )
>  ).
>
> And I was trying to rewrite it without all the if-then-elses. My first attempt (just to get rid of the outermost one), said that it was inferred as nondet, not det. Code is:
>
> :- pred euler1alt(int::in,int::out) is det.
>
> euler1alt(N,P) :-
>  (
>    N =< 0, P = 0
>  ;
>    not (N =< 0),
>    Np = N mod 3, Nq = N mod 5,
>    (if (Np = 0; Nq = 0)
>     then euler1alt(N-1,Ps), P = N + Ps
>     else euler1alt(N-1,P)
>    )
>  ).
>
> The error was:
> one.m:025:   Declared `det', inferred `nondet'.
> one.m:029:   Disjunction has multiple clauses with solutions.
> one.m:029:   call to `int.=<'(in, in) can fail.
> one.m:031:   Negated goal can succeed.
>
>
> I'm not sure why this change meant that there were now many or no solutions, as it seemed analogous to the if-then-else used above. The error specifies that =< can fail, but I would have thought that was covered by the not (N =< 0) case in the switch.
>
> What am I not understanding? I read the section on determinism and on goals (that talks about if-then-else having different semantics) in the reference manual, but I'm having a hard time figuring out how it is applying here, and how to fix the code!
>
The problem is that the determinism inference cannot determine that
N=<0, not (N=<0) are mutually disjunct, ie when one succeeds it
implies the other must always fail.

It may not be a lot of work to add detection of that special case, but
I would argue that in that case if-then-else is actually clearer.

If you wanted to use disjunction that was determininstic you could use instead.

compare(R, N, 0),
( (R = (=) ; R = (<) ),
...
; R = (>),
...
)

In this case the compiler knows all possible values of R and can
determine that only one branch of the disjunct will be taken.

However I still find the if-then-else to be much clearer to read.

--------------------------------------------------------------------------
mercury-users mailing list
Post messages to:       mercury-users at csse.unimelb.edu.au