1 unstable release

0.1.0 Dec 3, 2020

#1471 in Rust patterns

MIT license

44KB
850 lines

Lifted

Higher-kinded types for Rust. Implementation based on modifications to Liebow-Feeser's method, winding up at the same scheme described by Yallop & White.

Quickstart

Say you'd like to write a higher-kinded trait such as Functor. We can imagine it might someday look a bit like this:

trait Functor<A> {
    fn fmap<B, F: Fn(A) -> B>(me: Self<A>, f: F) -> Self<B>;
}

This isn't valid today, but with some minor changes we can write it:

use lifted::K1;

trait Functor {
    fn fmap<A, B, F: Fn(A) -> B>(me: K1<Self, A>, f: F) -> K1<Self, B>;
}

There are two key visible changes, and one hidden one:

  • rather than hypothetically parameterizing our Functor trait, we've moved the type parameter to the method itself,
  • rather than the hypothetical native Self<B>, we use a K1<Self, B> wrapper struct, and
  • rather than hypothetically implementing the trait for a half-baked type (e.g. Vec), we implement it for the HKT form VecC.

(Note that, while the term HKT form is borrowed from generic_std, the use of them here was discovered independently. On further review, the concept closely matches the brand from Yallop & White.)

The first two are more or less self-explanatory, but the third could use an illustration to clarify. Let's implement it!

use lifted::Kind1;

// Define the higher-kinded form of `Vec`
pub struct VecC;

// Specify how to construct a type instance
impl<T> Kind1<T> for VecC {
    type Inner = Vec<T>;
}

impl Functor for VecC {
    fn fmap<A, B, F: Fn(A) -> B>(me: K1<Self, A>, f: F) -> K1<Self, B> {
        let me = me.into_inner();   // unwrap the Vec<A>

        let you = me.map(f);        // map the Vec<A> to a Vec<B>

        K1::new(you)                // rewrap the Vec<B>
    }
}

For more details, please consult the API Documentation.

Documentation

API Docs

API docs are hosted on docs.rs:

API Documentation

Minimum Supported Rust Version

This crate makes use of no exotic language features, and so can support even very old versions of stable Rust. It has been tested successfully with Rust 1.35. (Once we get around to setting up CI, we will verify this MSRV with CI testing).

Comparison to other crates

  • Crate: generic_std
    • Purpose: generic traits for std types
    • Implementation: modified Smith's method, constructs a type instance from an HKT form
    • Maintenance: one experimental release
    • Notes: also considers lifetime kinds!
    • Notes: no concrete instance handling
  • Crate: fp-core
    • Purpose: a library for functional programming in Rust
    • Implementation: HKT trait constructs a type instance from another instance, macro to implement
    • Maintenance: no changes in the past year
  • Crate: rats
    • Purpose: an experimental, type-level functional programming library for Rust
    • Implementation: a god enum, traits, and type brands in some strange tango
    • Maintenance: no changes in the past 2 years
  • Crate: higher
    • Purpose: fake higher-kinded types with a minimum of boilerplate
    • Implementation: Lift trait constructs a type instance from another instance, derive macro to implement
    • Maintenance: one change in the past year
  • Crate: kinder
    • Purpose: algebraic structure and emulation of higher-order types
    • Implementation: Higher trait constructs a type instance from another instance, macro to implement
    • Maintenance: no changes in the past 4 years
  • Crate: archery
    • Purpose: abstract over atomicity of reference-counted pointers
    • Implementation: also based on Liebow-Feeser
    • Maintenance: active

Contributing

I'm happy to see any and all contributions, including bug reports, usability suggestions, patches, or angry yet well-intentioned rants. You are encouraged to report issues to the official issue tracker and send any questions or patches to the mailing list. Pull requests to the GitHub mirror are also acceptable.

No runtime deps