Quasi-approved HKTs for TypeScript:
https://github.com/Microsoft/TypeScript/issues/1213
In approximated Rust-esque:
trait Monad<T<*>> {
fn map<A, B>(f: &Fn(A) -> B) -> Box<Fn(T<A>) -> T<B>>;
fn lift<A>(a: A) -> T<A>;
fn join<A>(tta: T<T<A>>) -> T<A>;
}
trait Cartesian<T<*>> {
fn all<A>(a: Vec<T<A>>) -> T<Vec<A>>;
}
trait Foo<T<*, *>> {
fn bar<A, B>(f: Fn(A) -> B) -> T<A, B>;
}
Add lifetimes and the different Rust closures, and things get more "interesting"
Ah being able to specify a generic bound on a generic parameter would be interesting!
I wonder how it would hypothetically resolve T<*>
for A
where:
struct A;
impl Trait1<B> for A { }
impl Trait2<B> for A { }
I guess you could limit it on the struct definition and not traits, that example is actually a fairly flimsy argument.
emoon
June 15, 2016, 10:23am
3
Maybe I'm wrong but shouldn't topics like this go under the language design - Rust Internals section? (I know it was marked OT but still as it may spawn more interesting discussion over there)
I am sometimes shy in posting in the internals group, but you're right. Do you know if there's a way to move a thread there?
There is not, as they're totally separate instances.
eddyb
June 15, 2016, 2:59pm
7
Looks like the example uses Haskell-like syntax that ignores Self
and also has explicit currying, in Rust it would have to be:
trait<*> Monad {
fn map<A, B>(f: &Fn(A) -> B, ta: Self<A>) -> Self<B>;
fn lift<A>(a: A) -> Self<A>;
fn join<A>(tta: Self<Self<A>>) -> Self<A>;
}
trait<*> Cartesian {
fn all<A>(a: Vec<Self<A>>) -> Self<Vec<A>>;
}
trait<*, *> Foo {
fn bar<A, B>(f: Fn(A) -> B) -> Self<A, B>;
}
Although a syntax like trait Monad: type<type> {...}
is probably better suited for Rust.