rust-rats / rats

Categories for Rust
MIT License
5 stars 0 forks source link

Refactor Typeclasses to new format #41

Open pedrohjordao opened 3 years ago

pedrohjordao commented 3 years ago

One issue with the current representation is that we can't properly create bounds for a typeclass hierarchy:

trait Functor {
  type Outter<T>: Functor;
}

trait Apply: Functor {
  fn ap(...) -> Self::Outter<...>;
}

trait Applicative: Apply {
  fn pure(...) -> Self::Outter<...>;
}

Users of Apply will not be able to derive that Self::Outter is also an Apply since we are not able to update the bounds.

A simple example where this can show up is creating a general function to test homomorphisms:

fn applicative_homomorphism<T, A, B, F>(a: A, mut f: T<F>)
where
     T : Applicative,
     A : Copy,
     B : std::fmt::Debug + std::cmp::PartialEq,
     F : Copy + FnMut(A) -> B,
{
    assert_eq!(T::pure(a).apply(f), f.apply(T::pure(|mut fun: F| fun(a))));
}

In the current setup, all we know about a general T::pure(a) is that it is a type that implements Functor. We aren't able to automatically derive that it is also an Apply and Applicative. Representing this bounds would get exponentially more complicated.

With this in mind we started looking for a new representation for the typeclases.

Based on the original post motivating GATs plus some experimentation we were able to derive a new representation that is able to work for generic functions with a nice-enough API that could be improved as GAT support improves.

Proof of concept implementation: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=cdcb8961e9d8d41b14d137625d33b1ad