existential types (was: univ and functor/arg)

Fergus Henderson fjh at mundook.cs.mu.OZ.AU
Wed Apr 30 00:03:23 AEST 1997


I wrote:

>Currently there is a big limit to what you can do with `univ', because
>although you can convert a value to type univ, and you can convert a
>univ back to any given ground type that you know at compile time, there
>is no way to convert a univ back to a type which is not fully known at
>compile time; that means that for example if you have a univ, then
>although you can pass the univ itself to a polymorphic predicate, you
>can't pass the value stored in the univ to a polymorphic predicate.

This limitation is in fact very bad.  I keep running into it.
I'm just writing hash/1 and I find that in order to avoid this
problem, I need to have a hash_univ/1.  Duplicating the interface
is bad enough already, but in this case I also need to duplicate the code. 
For efficiency I don't want to do

	hash(X) = hash_univ(univ(X)).

because that would require a memory allocation (to create the univ)
for every call to hash/1, so instead I'm forced to have two copies
of the same code, one for hash/1 and one for hash_univ/1.

In my previous mail I proposed extending explicit type qualifications
to handle this:

>	expand_univ(Univ, F, N, Args) :-
>		expand(univ_value(Univ) : { univ_type(Univ) }, F, N, Args).

However, I've realized there is a much nicer answer that solves the
problem perfectly: existential types.

The type declaration for `univ_value' should be changed to use an
existential qualifier: instead of

	:- func univ_value(univ) = T.	% T implicitly universally quantified
	:- mode univ_value(in) = out is semidet.

it would be declared as

	:- some [T] (func univ_value(univ) = T).
	:- mode univ_value(in) = out is det.	% NB det not semidet, because
						% it does not need a type test

Then you could just write

	expand_univ(Univ, F, N, Args) :-
		expand(univ_value(Univ), F, N, Args).

and indeed there'd be no need for a separate expand_univ.

Implementation-wise, the type_info argument for an existentially
qualified type variable would have mode `out' rather than the usual
`in' mode that is used for universally qualified type variables.
Type checking and mode analysis would both need changes to handle
existential types.

I think this is definitely the right solution, but unfortunately
implementing it will require quite a significant amount of work.

In the short term I guess we'll just have to have two versions
of everything that calls expand/4, functor/3, or argument/3.

--
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the developers mailing list