[mercury-users] discriminant types, generators

Fergus Henderson fjh at cs.mu.OZ.AU
Mon Jul 14 01:48:46 AEST 2003

On 13-Jul-2003, Matthias Kretschmer <mccratch at gmx.net> wrote:
> I have the following problem, want to do the following task:
> having some discriminant type, say
> :- type mytype ---> a ; b ; c ; d.
> maybe used by some other type, say
> :- type othertype ---> someint(int) ; intandmytype(int, mytype).
> Now I want to define some predicate that can be used to generate a list 
> of intandmytype(2, X) for all X in mytype.
> I thought of something like this:
> :- pred mypred(othertype).
> :- mode mypred(out) is multi.
> mypred(someint(2, _)).
> and using solutions/2 from std_util for generating a list using mypred.
> but the compiler complains about a mode error.

Right.  That is a deliberate design decision.  The code that you
wrote makes sense declaratively, but the compiler does not attempt to
automatically bind variables for you; inserting nondeterministic code
to bind variables when the programmer didn't write it explicitly would
make the operational semantics too subtle, and might also mask accidental
errors where the programmer simply forgot write the part of the code
which would bind the variable.

> The only solution I come 
> up with, was some extra predicate, lets say
> :- pred is_mytype(mytype).
> :- pred is_mytype(out) is multi.
> is_mytype(a). is_mytype(b). is_mytype(c). is_mytype(d).

Right.  And then mympred/1 will call is_mytype/1:

    mypred(someint(2, X)) :- is_mytype(X).

> but I don't really like to have to do this this way. Is there any other 
> solution?

Yes, there is.  The code for mypred/1 does need to explicitly call a
generator predicate.  But you don't have to write the generator
predicate by hand for every type.  It's quite simple to use the facilities
in the `construct' module to write a generator that will work for any
enumeration type:

    :- import_module construct, list, int, std_util, type_desc.

    gen_enum(Val) :-
	Type = type_desc__type_of(Val),
	list__member(FunctorNum, 0 `..` (construct__num_functors(Type) - 1)),
	Univ = construct__construct(Type, FunctorNum, []),
	std_util__det_univ_to_type(Univ, Val).

Then you can use this generic definition of gen_enum/1 in my_pred/1:

    mypred(someint(2, X)) :- gen_enum(X).

Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe

More information about the users mailing list