[m-dev.] Re: proposal: user-defined equality predicates

Andrew Bromage bromage at cs.mu.oz.au
Fri Jun 27 16:03:17 AEST 1997


G'day.

Peter Schachte wrote:

> My rationale for wanting this is that non-canonical types don't work in
> Mercury (or any other logic programming language I know of).  Fergus'
> set-as-unordered-list example illustrates it quite well.

I understand why implementing sets as unordered lists and defining
equality on them in a nice way is a good idea.  However I think that
it is incorrect to overload =/2 in this way.  What I think would be
better is to handle this in type classes...

> If sets are
> implemented as unordered lists, *users* of that type have to be very
> careful never to unify two such entities, or they may get the wrong
> result.

...with perhaps some new feature to prevent people from using
unification/compare/whatever where it is not meaningful to do so.

> > 	- (X = Y) => (p(X) <=> p(Y))
> 
> Aside from the caveat Fergus put in the footnote, and aside from problems 
> the compiler will complain about when you have a goal that can fail after 
> a deconstruction (which will be cc_multi) I think this property is
> maintained.  I'm sure Fergus can argue this more convincingly.

Some code speaks a thousand words, so here goes.  Here's a new
replacement for the `unit' type implemented using the current
installed compiler and using ideas from the proposed equality
system:

<< new_unit.m
:- module new_unit.
:- interface.

:- type new_unit.

:- pred new_unit_equals(new_unit :: in, new_unit :: in) is semidet.

:- func new_unit_1 = new_unit.
:- func new_unit_2 = new_unit.
:- func f(new_unit) = int is det. % Should this be cc_multi?

:- implementation.

:- type new_unit
        --->    new_unit(int).
        % where equality is new_unit_equals.

	% This is indeed an equivalence relation.  It also
	% encapsulates the intuitive meaning of `unit'.
new_unit_equals(_X, _Y).

	% Must deconstruct using this function only.
:- func deconstruct_new_unit(new_unit) = int is cc_multi.
deconstruct_new_unit(new_unit(X)) = X.

new_unit_1 = new_unit(1).
new_unit_2 = new_unit(2).
f(NewUnit) = deconstruct_new_unit(NewUnit).
>>

<< test.m
:- module test.

:- interface.
:- import_module new_unit, io.

:- pred main(io__state :: di, io__state :: uo) is det.

main -->
        ( { new_unit_equals(new_unit_1, new_unit_2) } ->
                io__write_string("X = Y\n")
        ;
                io__write_string("X \\= Y\n")
        ),
        ( { f(new_unit_1) = f(new_unit_2) } ->
                io__write_string("f(X) = f(Y)\n")
        ;
                io__write_string("f(X) \\= f(Y)\n")
        ).
>>

And the output is...

<<
X = Y
f(X) \= f(Y)
>>

Either the current determinism checker inferred the wrong determinism
for f (should be cc_multi) or det functions are no longer single valued
under the new scheme.

> > 	- It always terminates.  If you ignore higher-order values.
> 
> and functions.

Okay, qualification: unifying two variables always terminates.
Unifying with a function is unifying with the result of a call.

Cheers,
Andrew Bromage



More information about the developers mailing list