# [mercury-users] Switches and "subswitches"

Ondrej Bojar oboj7042 at ss1000.ms.mff.cuni.cz
Sun Sep 30 21:26:47 AEST 2001

```Hello.

I quite often face a problem with switches and "subswitches". (I hope
you'll find switches and subswitches in the following code, I'm really
unable to describe the notion in English.)

I want to write code like this: (line numbers supplied)

15 :- type type_a ---> a_a; a_b; a_c.
16 :- type type_b ---> b_a; b_b.
17
18 :- type type_c ---> c_a_a; c_anything_b; c_b_a; c_c_anything.
19
20 % the two_to_and_from_one is to convert information supplied
22 :- pred two_to_and_from_one(type_a, type_b, type_c).
23 :- mode two_to_and_from_one(in, in, out) is det.
24 :- mode two_to_and_from_one(out, out, in) is multi.
25
26 % of course the real conversion is a bit more complicated
27 % usually I do some calls *after* the unifications
28 two_to_and_from_one(a_a, b_a, c_a_a).
29 two_to_and_from_one(a_b, b_a, c_b_a).
30 two_to_and_from_one(a_c, B, c_c_anything) :-
31   B = b_a; B = b_b.
32 two_to_and_from_one(A, b_b, c_anything_b) :-
33   A = a_a ; A = a_b.

...And now the error message

testswitches.m:023: In `two_to_and_from_one(in, in, out)':
testswitches.m:023:   error: determinism declaration not satisfied.
testswitches.m:023:   Declared `det', inferred `nondet'.
testswitches.m:028:   In argument 2 of clause head:
testswitches.m:028:   unification of `HeadVar__2' and `testswitches:b_a'
can fail.
testswitches.m:029:   In argument 2 of clause head:
testswitches.m:029:   unification of `HeadVar__2' and `testswitches:b_a'
can fail.
testswitches.m:032:   In argument 2 of clause head:
testswitches.m:032:   unification of `HeadVar__2' and `testswitches:b_b'
can fail.
testswitches.m:033:   The switch on A does not cover testswitches:a_c/0.
testswitches.m:028:   Disjunction has multiple clauses with solutions.

I suppose, Mercury is not able to find out that for example the case of
input variables a_a, b_b is covered with the last clause. And Mercury
tries to get the answer in the first clause already. A solution would be
to parse the input variables in exact order, as a decision tree: (the
switches and subswitches notion)

if A = a_a
then
if B = b_b
then C = c_anything_b
else C = c_a_a
else
...

But this solution will lead to I-dont-know-what code when the other mode
of the predicate is to be build.

Another solution would be to list all possible cases one by one:

two_to_and_from_one(a_a, b_a, c_a_a).
two_to_and_from_one(a_a, b_b, c_anything_b).

But this solution is not too "typing-efficient" and is absolutely useless
when string or int comes as the input variable type... (Which is my case.)

Is there a better way of writing such code?

(In the example above, the c_anything_b and c_c_anything combination is
deliberate. Sometimes, only the first input is important, sometimes only
the other is.)

What also fails is using negation:

two_to_and_from_one(A, b_b, c_anything_b) :-
A \= a_c.

This leads to a mixed-mode error, as Mercury is (naturally) not able to
find all possilbe values for A different from a_c when building mode (out,
out, in).

It might happen, that I even forget some cases when writing the code... I
love Mercury for showing me mistakes like that, but here the situation is
a bit too complicated, so Mercury can't explain what did I wrong...

Thanks for any tips on rewriting the code.

Andrew.

--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au