-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A simple try for HKT #40368
A simple try for HKT #40368
Conversation
Cool! Could you fix the test cases(or lint or merge master) and we could pack this. |
Alright, finally...... |
seems not work again.... |
Oh, I see the cute little green check mark and would not push any more until it is packed this time |
@typescript-bot pack this |
@typescript-bot pack this. |
Hey @Kingwl, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running There is also a playground for this build and an npm module you can use via |
I've tried this out locally and it's really interesting. The tests pass and I'm able to use it in VSCode. Is there anything I can help with here? Testing? |
@jeremiahrhall Thanks a lot for the kind willing! I have almost forgot this PR..... for many reasons:
And, yes, of course, testing this would be really helpful, especially when it could fit all your need. I am curious whether it is a common partten without needing constraint. If so, perhaps we could argue a bit with TS Team! |
@ShuiRuTian |
Thanks for the kind willing. Some parts of the link looks good. However, other parts are basic and lack details. It would be better if you could give more detailed design.
interface MyGeneric<T extends string>{}
const foo: MyGeneric<number>; // error, number is not string And in HKT, this is much more complex interface MyGeneric1<T extends string>{}
interface MyGeneric2<T extends number>{}
interface MyFunctor<G<T extends string> extends MyGeneric1<T>>{}
const foo: MyFunctor<MyGeneric2>; // error, number is not string, and MyGeneric2 is not MyGeneric1
// Think about three kinded HKT, it would be complex.
// Look this:
// interface HKT3<Functor<Generic1<T extends number> extends Generic2<T>, Generic2<U exnteds V> exnteds Set<V>>, V extends string>
// Is HKT3 valid?
// If we have HKT3<FunctorImpl, string>, should this be valid? The conclution is type parameter should be cotravariance, and return type should be covariance.
I do not have many idea about this, but it must be difficult. And here is one question I am not sure: |
HKT3 certainly cannot be valid type Foo<V extends string, U extends V> = U
type Bar<V extends string, T extends number> = Foo<V, T>
// Type 'T' does not satisfy the constraint 'V'.
// 'V' could be instantiated with an arbitrary type which could be unrelated to 'T'.
// Type 'number' is not assignable to type 'V'.
// 'V' could be instantiated with an arbitrary type which could be unrelated to 'number'. V is passed in like a closure interface MyGeneric1<T extends string>{}
interface MyGeneric2<T extends number>{}
interface MyFunctor<
G extends for<T extends string> MyGeneric1<T>
>{}
const foo: MyFunctor<MyGeneric2>; I think my syntax is more readable and easier to think interface HKT3<
Functor extends for<
Generic1 extends for<T extends number> Generic2<T>, // T error
Generic2 exnteds for<U exnteds V> Set<V>
>,
V extends string
> How to write FunctorImpl ? interface FunctorImpl<
Generic1 extends for<T extends number> Generic2<T>, // T error
Generic2 exnteds for<U exnteds string> Set<string>
> { }
// or
type G2<U exnteds string>= Set<string>
type G1<T extends number> = G2<T> // T error
interface FunctorImpl<
Generic1 extends G2,
Generic2 extends G1,
>{ } for<U exnteds string> Set<string> <- for<U extends string | number> Set<'a'>
// just like
(u: string) => Set<string> <- (u: string | number) => Set<'a'>
If a type constructor is not applied there is no partial application type Foo<T> = T
type Bar = Foo // Bar is type Bar<T> = T
type Foo<T> = for<U> T | U
type Bar = Foo<1> // Bar is type Bar<T> = 1 | T |
This experiment is pretty old, so I'm going to close it to reduce the number of open PRs. |
@sandersn, your development lead approved the approach and asked for a draft implementation — #1213 (comment). The case with one type parameter is basically what we need in 95%, e.g. interface Functor<F<_>> {
map<A, B>(f: (a: A) => B): F<A> => F<B>;
} I hope you have closed this PR to continue working on the implementation within the Microsoft team, as the HKT topic is enormously in demand — you can look at the related discussion. For a reference, you can take an advanced Scala compiler and their HKT implementation. |
Fixes #1213
Far from complemention, just a try for now.
Two list, one is added ability, one is added error check.
Ability
// from communicity
Error
Here are some simple thoughts about constraints.
Most from scala.
Convert
Type Constructor Instance
toType Lambda
List = [T] =>> List[T]
Convert
apply constraint
toType Lambda
type T[X] >: L <: U
convert totype T >: ([X] =>> L) <: ([X] =>> U)
Define
<:
onTypeLambda
:type TL1 = [X >: L1 <: U1] =>> R1
type TL2 = [X >: L2 <: U2] =>> R2
TL1 <: TL2
ifL2..U2
is contained in the type intervalL1..U1
(i.e.L1 <: L2
andU2 <: U1
) andR1 <: R2
The conditions are reasonable: assume we have
interface F[G[T<:U1] <: G1[T]]
,G[Timpl]
, soTimpl <: U1
,then we replace
G[T]
withGimpl[U<:U2] <: G2[U]
, if the U is stricter(U2<:U1
), Timpl might not meetTimpl <: U2
;And we use functions in
G1[T]
, ifG2[U] <: G1[T]
these functions might not exist.If
A <: B
A
andB
both have met the contraints.TypeLambda[A] = TypeLambda[B] is valid if TypeLambda[+T];
TypeLambda[B] = TypeLambda[A] is valid if TypeLambda[-T];