haskpy.types.compose.Compose

Compose(X, Y)[source]

Compose two type constructors X and Y into a single type constructor

Kind:

Compose :: (* -> *) -> (* -> *) -> * -> *

That is, it takes two type constructors and one concrete type to create a concrete type. Another way to see it is that it takes two one-argument type constructors and returns a one-argument type constructor:

Compose :: (* -> *) -> (* -> *) -> (* -> *)

That’s how we can see it here.

Two nested Applicative structures are merged into one layer:

Composed :: f1 (f2 a) -> f f1 f2 a

Note that f is a type constructor of three arguments as shown by its kind above.

Some motivation for the current implementation:

  • Why not just a class that takes a value/object? Why do we need this function wrapper Compose that takes classes as arguments? Because we need to be able to implement the class method pure. Also, this solution would make it possible to decide the parent classes based on the classes of X and Y, so that composed result isn’t, for instance, Foldable unless both X and Y are Foldable.

  • Why the class Composed doesn’t have __init__ that passes *args and **kwargs to the outer class constructor? It would make it slightly more convenient to create values, right? Not really. We want to be able to transform already existing non-composed values to composed values. For that we need to just take a value, not the outer class constructor arguments. Also, this allows us to decompose and compose in turns without problems. Also, it is more explicit for the user that which are the underlying types because they need to write those when creating values.

So, in comparison to Haskell, the function Compose corresponds to type-level composing and Composed corresponds to value-level type converter. We need explicit type-level composing here because we need some class methods such as pure.