|
It's easier to make the parallel between type-level and value-level reasoning. 1 is a value, and int is a concrete type. function increment(x) { return x + 1 } is a value-level function. You feed it a value x and you get a value back. List<T> is a type-level function: you give it a concrete type T, you get another type back. function applyTwice(f, x) { return f(f(x)) } is a higher-order function that takes a functions as an input. A higher-kinded type is a higher-order type function. As a concrete example, consider this pseudo-Java method: List<B> map<A,B>(Function<A,B> fn, List<A> as) { ... }
You take a list, and you return a list. Thing is, Java has several list implementations: LinkedList, ArrayList, CopyOnWriteArrayList, and a few others. What I'd like to express is that whatever concrete list type goes in is also the concrete type that comes out. If java allowed it, you could express it like this: L<B> map<L<T> extends List<T>,A,B>(Function<A,B> fn, L<A> as) { ... }
This map is generic on L, A, and B, but also L is itself generic, so map is "twice-generic", if you will. |