[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
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