[mercury-users] higher order types + type class constraints

Fergus Henderson fjh at cs.mu.OZ.AU
Tue Nov 28 19:30:34 AEDT 2000

On 28-Nov-2000, Michael Day <mikeday at corplink.com.au> wrote:
> How does one pass around higher order terms that have type class
> constraints?

You can't.  In fact you can't pass around polymorphic higher-order
terms at all.  Mercury does not directly support "first class polymorphism".

However, there is a work-around: you can achieve the same effect using
type classes and existential types.

> This is not correct:
> :- pred foo(pred(C, C) <= something(C), other args ...).
> :- mode foo(pred(di, uo) is det, other args ...) is det.

Right.  That is almost the syntax that we'd use if we were to support
first class polymorphism; however, we'd use an explicit quantifier:

	:- pred foo(all [C] (pred(C, C) <= something(C)), other args ...).

> While this compiles, but doesn't work:
> :- pred foo(pred(C, C), other args ...) <= something(C).
> :- mode foo(pred(di, uo) is det, other args ...) is det.
> foo(P, others ...) :-
> 	create C0,
> 	P(C0, C)		% error here, expects type to be `C'

Yes, you get an error here, because `P' is monomorphic at this point;
the type `C' must be determined by the caller of `foo'.

> Any suggestions?

The work-around goes like this.
Define a typeclass with a single method whose type matches
the type of the higher-order pred term that you want to pass,
but with the typeclass parameter as an additional argument:

	:- typeclass my_poly_pred(T) where [
		(pred call_it(T, C, C) <= something(C)),
		(mode call_it(in, di, uo) is det)

Then change your predicate which gets passed this higher-order term
so that it instead gets passed a value of this typeclass:

	:- pred foo(Pred, other args ...) <= my_poly_pred(Pred).
	:- mode foo(in, other args ...) is det.

	foo(P, others ...) :-
		call_it(P, C0, C).

Then, instead of calling `foo' as 

		foo(bar, ...)

you would define a dummy type called as `bar_t'
(or just `bar' if you prefer),

	:- type bar_t ---> bar_t.

make that type an instance of the typeclass you defined earlier,
and have the method call `bar':

	:- instance my_poly_pred(bar_t) where [
		call_it(_, C0, C) --> bar(C0, C)

Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  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