Skip navigation links

Package com.mojang.datafixers.kinds

Contains common type classes and interfaces that allow the use of higher kinded types.

See: Description

Package com.mojang.datafixers.kinds Description

Contains common type classes and interfaces that allow the use of higher kinded types.

A higher kinded type, or type constructor, is a type that accepts type parameters. For example, the parameterized type List<String> is an application of the type constructor List<_> with the type String. In type theory, it is said that the kind of the type List<_> is * -> *, so called because it accepts one (non-higher kinded) type argument and produces a type.

Most of the type classes defined in this package are for types of the kind * -> * (the kind * is the kind of regular types). For types that take more than one type parameter, such as Either or Function (both of kind * -> * -> *), the first type argument is fixed when defining type classes.

Type Classes

A type class is similar to the concept of a Java interface. Conceptually, a type class defines a collection of functions that must be implemented by any instances of that type classes. However, unlike Java interfaces, instances of type classes are not objects. Rather, a type class instance is a singleton value that is associated with the type that the instance is defined for. As well, the functions defined in type classes are often "static"; that is, they often do not take a parameter of the type they are defined for. For example, the type DataResult has a type class instance DataResult.Instance which implements both the Functor and Applicative type classes.

Programmers familiar with the Rust programming language may recognize this concept of type classes, as they are extremely similar to the Rust concept of traits. Programmers familiar with Haskell may also recognize the concept of type classes, as Haskell itself has a concept of type classes.

Writing Higher Kinded Types

Writing code that is generic over different applications of higher kinded types poses a difficulty in Java, as the language does not have native support for declaring type variables of higher kinds. In order to address this difficulty, DFU provides two sets of interfaces.

The K1 and K2 interfaces represent higher kinded types that take one and two type parameters, respectively. Each higher kinded type declares a nested witness type that inherits from either K1 or K2 depending on the number of type parameters that are required to be bound. These witness types are typically empty classes and are never instantiated. Rather, they are used purely to represent the higher kinded type in places where the unapplied type constructor must be passed. In DFU, these nested witness types are called Mu, or some variation of. Note that sometimes witness type interfaces in DFU themselves declare type parameters; such a witness represents a partially applied version of the higher kinded type.

The App and App2 interfaces are used to apply one or two types to a type constructor, respectively. The first parameter to both interfaces is a witness type of a type constructor (of one or two parameters, respectively). The remaining parameters correspond to the type parameters declared in that type constructor. In this fashion, different applications of a given higher kinded type may be written using different parameterizations of App. For example, the type DataResult<String> may be written as App<DataResult.Mu, String>, and in general the type F<T> may be written as App<F.Mu, T>.

Rendering

In the HTML rendering of this documentation produced by this custom doclet, parameterizations of App and App2 are rendered using the more intuitive form F<T> mentioned previously. In fact, parameterizations of higher kinded types using App and App2 are rendered exactly like parameterizations that use the higher kinded type directly. Additionally, all type classes are rendered as TypeClass F, where F is the higher kinded type that the type class is defined for. In reality, type classes in DFU declare additional type parameters, but these additional parameters are unnecessary to understand the types being used.

To get an idea of what the custom rendering does, take this method in ListBox.Instance.


 <F extends K1, A, B> App<F, App<ListBox.Mu, B>> traverse(
      Applicative<F, ?> applicative,
      Function<A, App<F, B>> function,
      App<ListBox.Mu, A> input)
 

Using the custom rendering, the method signature appears like this.


 <F extends K1, A, B> F<ListBox<B>> traverse(
      Applicative F applicative,
      (A) -> F<B> function,
      ListBox<A> input)
 
See Also:
Type Class
Skip navigation links