[][src]Crate higher

This crate implements a mechanism to fake higher kinded types in a limited way in Rust with a minimum of boilerplate.

But Why?

If you ever had a trait T<A> and wanted to swap the type parameter out in a generic way to produce a type T<B> in the trait's type signatures, there's no straightforward way to do this currently in Rust, because this would require Rust's type system to support higher kinded types. It can deal with T<A> but it can't deal with the concept of just T where the type parameter is yet unspecified (what's known as a type constructor - think of it as a function which takes a type parameter, like A, and returns a concrete type T<A>).

higher provides the trait Lift which, when given a type T<A> which implements Lift<A, B>, will let you derive the concrete type T<B>. This needs to be implemented for any T<A> which needs Lifting, but the higher-derive crate provides a custom derive for it, so that you can quickly add it to your own types without boilerplate:

#[derive(Lift)]
enum MyLittleOption<A> {
    Definitely(A),
    NotReally,
}

Now, to convert from T<A> to T<B>, you can get the Target1 associated type out of the Lift trait:

<MyLittleOption<A> as Lift<A, B>>::Target1
// this resolves to MyLittleOption<B>

There is also the Lift3<A, B, C> trait, which is also generated by the Lift derive, which lets you go from T<A> to both T<B> and T<C> in one go. This is useful if you need an intermediate type in one of your type signatures, for instance a zip or merge function: Fn(T<A>, T<B>) -> T<C>.

Here is how to use the above example type with Lift3:

<MyLittleOption<A> as Lift3<A, B, C>>::Target2
// this resolves to MyLittleOption<B>
<MyLittleOption<A> as Lift3<A, B, C>>::Target1
// this resolves to MyLittleOption<C>

// the numbers go from right to left, so Target1 = C and Target2 = B.

Further, there's the Bilift<A, B, C, D> trait, for when you have two type parameters to generalise over. This one takes you from T<A, B> to T<C, D>. There's no corresponding Bilift3 trait as yet, because I haven't found a practical need for it yet.

There's a corresponding derive for Bilift:

#[derive(Bilift)]
enum MyLittleResult<A, E> {
    Grand(A),
    NotGrand(E),
}

And, to get the derived type out of the Bilift:

<MyLittleResult<A, B> as Bilift<A, B, C, D>>::Target1
// this resolves to MyLittleResult<C, D>

Yes, But Why, Really?

Because sometimes one just gets homesick for Haskell and wants to implement the Functor hierarchy. You'll find this in the higher-cat crate. It's not really very suited for writing good Rust code, but it makes Haskell programmers feel happy and it has a lot of funny words.

Traits

Bilift

Bilift lets you construct a type T<C, D> from a type T<A, B>.

Lift

Lift lets you construct a type T<B> from a type T<A>.

Lift3

Lift3 extends Lift to let you construct two types T<B> and T<C> from a type T<A>.