[mercury-users] Dynamic typecasts to polymorphic types

Fergus Henderson fjh at cs.mu.OZ.AU
Thu Sep 21 14:48:40 AEDT 2000


On 20-Sep-2000, Ralph Becket <rbeck at microsoft.com> wrote:
> I has looking at the pprint code and thought it would be nice if the
> generic to_doc/2 function spotted lists and generated [x, y, z] style
> output rather than '.'(x, '.'(y, '.'(z, []))) as it currently does.
> 
> My attempt at this went along the following lines:
...
> :- func my_to_doc(T) = doc.
> 
> my_to_doc(X) = ( if cast(X, Xs) then to_list_doc(Xs) else to_doc(X) ).
> 
> :- pred cast(X::in, Y::out) is semidet.
> 
> cast(X, Y) :- univ_to_type(univ(X), Y).
> 
> :- func to_list_doc(list(T)) = doc.
...
> This results in a warning:
> 
> foo.m:013: In function `foo:my_to_doc/1':
> foo.m:013:   warning: unresolved polymorphism.
> foo.m:013:   The variable with an unbound type was:
> foo.m:013:       Xs :: (list:list(T))
> foo.m:013:   The unbound type variable(s) will be implicitly
> foo.m:013:   bound to the builtin type `void'.
> 
> and to_list_doc/1 never gets called.

We should probably change that to an error rather than a warning.

> If I change its signature to
> 
> :- func to_list_doc(list(int)) = doc.
> 
> then at least [1, 2, 3, 4] gets printed as required.  The problem is
> obviously that univ_to_type(X, Y) only works if the type of Y is
> identical to that of X, rather than just subsuming it.  Is this a
> bug?

No.

In Mercury (unlike in TEL and HAL) all the types that are passed
around at runtime are ground types.  This simplifies the implementation
considerably, and improves efficiency a little.  It might also make
interoperability with other languages that support parametric
polymorphism easier.

As a result, a predicate like your cast/2 always gets passed
two ground types, and so it can only ever do a groundness check,
not a subsumption check.

> If not, I suspect we need another predicate that does as required.

You can achieve the effect that you're looking for using
the following technique:

	:- some [T2]
	   pred cast_to_list(T1::in, list(T2)::out) is semidet.

	cast_to_list(Object, List) :-
		% figure out the list element type
		type_ctor_and_args(type_of(Object), _, [ElemType]),

		% constrain the type of `List' to be list(ElemType)
		has_type(Elem, ElemType),
		same_type(List, [Elem]),

		% now the type of `List' is ground, so we can just
		% perform an ordinary cast
		cast(Object, List).

	% This could/should go in a library...
	:- pred same_type(T::unused, T::unused) is det.
	same_type(_, _).

Another way that could be used would be by calling std_util__construct/3
with an existentially quantified constructor:

	:- type t ---> some [T] t(list(T)).

	cast_to_list(Object, List) :-
		simple_construct(Object) = t(List).
	
	% This could/should go in a library...
	:- func simple_construct(ArgT) = T is semidet.
	simple_construct(Object) = Result :-
		univ_to_type(construct(type_of(Result), 0, [univ(Object)]),
			Result).

This method would be nicer, since it is simpler, and it extends more
easily to arbitrary pattern matching.  For example, if you want to
check that a type has the form `map(K, V)' or `map(T, T)', or that a
type has the form `list(T)' where T is an instance of the printable/1
type class, you could do the same thing as above, only using one of
these types instead of `t':

	:- type t2 ---> some [K, V] t2(map(K,V)).
	:- type t3 ---> some [T]    t3(map(T,T)).
	:- type t4 ---> some [T]   (t4(list(T)) => printable(T)).

However, currently we don't support std_util__construct/3 for
existentially quantified constructors, so you need to stick with
the technique I mentioned first.

-- 
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.
--------------------------------------------------------------------------
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