higher order generics
See original GitHub issue[@gavinking] We’ve often discussed this feature, type constructor parameterization, or kinds, or whatever you want to call it, which boils down to, by analogy with first-class/higher order functions at the value level, adding:
- first-class type constructors, and
- higher-order generic declarations.
That is, I can define generic types and functions which are parameterized not only by types, but also by type constructors. And I can pass a reference to a type constructor as an argument to such a generic type or function.
I now have an implementation of higher order generics in the typeconstructors
branch of the typechecker project. An outline of my approach:
-
Type constructors are represented as types within the type system, just like functions are represented as values. This is much less significant than it sounds, since type constructors have no meaningful subtype relationships with other types, but it does let us avoid introducing a whole new level of the type system. In particular, it means that a type parameter that accepts type constructors is still just a type parameter, not some new kind of thing.
-
The syntax
@List
produces a reference to a type constructor for a generic type declaration. In principle, we could live without the@
, but that would make it awfully difficult to distinguish type constructors for ordinary unparameterized types, so I think the@
is a good thing. Reiterating what I said above,@List
is considered a type. It’s not, however, meaningful to ask what its values are. Nor does it have any interesting subtype relationships with other types. (Indeed,@List
might not even be a subtype ofAnything
.) -
A generic declaration may have a parameter that accepts type constructors. The syntax is:
interface Functor<@Fun> given Fun<Element>
The
@
is a visual indication that the parameter expects a type constructor, and thegiven
clause defines the signature required. We could simplify the syntax tointerface Functor<Fun<Element>>
, but I find this a lot less self-explaining. -
Within the body of such a parameterized declaration, the type parameter is a parameterized type like any other parameterized type. I can write, for example:
interface Functor<@Fun> given Fun<Element> { shared formal Fun<Out> map<In,Out>(Out apply(In a)) (Fun<In> inFun); }
-
Finally, I can instantiate the generic declaration by giving it a conforming type constructor:
object listFunctor satisfies Functor<@List> { ... }
-
Now, with just this much machinery I can write code that abstracts over functors, for example:
Fun<String> toString<@Fun>(Functor<@Fun> functor) (Fun<Object> inFun) given Fun<Element> => functor.map(Object.string)(inFun);
There’s one big limitation remaining in the current implementation: I don’t have type constructor arg inference, so I have to write shit like this:
List<String>(List<Object>) listToString = toString<@List>(listFunctor);
Instead of just:
List<String>(List<Object>) listToString = toString(listFunctor);
I assume that this problem is tractable.
Otherwise, the implementation was surprisingly easy and straightforward though surely there are still a couple of holes.
Now, the only reason I’ve even bothered playing around with this shit at this stage is that we have an actual use for it in the metamodel API. We would like to be able to have typesafe model objects for generic declarations. That is, it would be nice to be able to write:
GenericClass<@List> listGenClass = `@List`;
Class<List<String>> stringListClass = listGenClass(`String`);
And have that be all totally typesafe.
UPDATE: Note, we no longer propose to use this stuff for the metamodel!
What I’m not proposing at all is to go and make Iterable
and its subtypes into Functor
s. It would be possible to do this someday, if we decide it’s truly useful, but I definitely don’t want to do it in Ceylon 1.x.
So, we need to decide if we’re going to make this a part of the language. There are strong arguments on both sides, which I’ll let others advocate, because I simply can’t seem to make up my mind.
[Migrated from ceylon/ceylon-spec#754]
Issue Analytics
- State:
- Created 10 years ago
- Comments:97 (5 by maintainers)
[@luolong] Note to self: that soundbite from @RossTate sounds like a true gobbledygook to me 😉
Yes, sorry, of course.