I don’t think the recent type system changes provide higher-order generics exactly. I believe https://github.com/JuliaLang/julia/issues/18466 captures what something like this feature would look like in julia. E.g. you could define
type Compose{C1, C2, T}
data::C1{C2{T}}
end
Julia doesn’t really have a kind system in the usual sense. The type system does not classify types according to what parameters they are able to accept. Indeed it does not model “type application” at all; that only takes place as part of execution (semantically of course). The type system only sees “fully formed” types, and has very little idea how they got that way. So it’s not the case that Vector{Int}
is a type and Vector
is a type constructor. Rather they are both just types, the latter being less specific. The fact that Vector
can be applied to a parameter with { }
is worked out at run time based on its representation. In theory, you can have a type equal to Vector
that cannot be applied to a parameter, for example Union{Vector, Vector}
.
We typically get around the lack of e.g. a kind system by saying, if you need anything fancier, just use normal functions! For example
compose(C1, C2, T) = C1{C2{T}}
or other things like the eltype
or promote_type
functions. These are obviously Turing complete, so if you can’t do what you want it’s rather suspicious The remaining debate is then only about which things must be types, vs. which things are arbitrary expressions that get evaluated at some point. In the case of #18466, currently field types need to be types but we could relax that and allow them to be expressions.