Skip to content
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

Higher Kinded Types #152

Open
Caleb-T-Owens opened this issue Jun 10, 2022 · 5 comments
Open

Higher Kinded Types #152

Caleb-T-Owens opened this issue Jun 10, 2022 · 5 comments

Comments

@Caleb-T-Owens
Copy link

Hello, I just wanted to draw attention to microsoft/TypeScript#1213 which outlines discussion about syntax for higher kinded types which greater enable the implementation of chainable APIs

For example: this implementation of a chainable object will revert back to the super type Mappable<B> when .map() is called on OtherMappable

class Mappable<A> {
    constructor(protected value: A) {}

    newThis<B>(b: B) {
        return new Mappable<B>(b)
    }

    map<B>(fn: (a: A) => B): Mappable<B> {
        return this.newThis(fn(this.value))
    }
}

class OtherMappable<A> extends Mappable<A> {
    newThis<B>(b: B) {
        return new OtherMappable<B>(b)
    }

    getValue() {
        return this.value
    }
}

console.log(
    new OtherMappable(3)
        .map((a) => a + 1)
        .getValue() // Property 'getValue' does not exist on type 'Mappable<number>'.(2339)
)

The proposed syntax would look like

class Mappable<A> {
    constructor(protected value: A) {}

    newThis<B>(b: B) {
        return new Mappable<B>(b)
    }

    map<B, F<~> extends Mappable<~>>(fn: (a: A) => B): F<B> {
        return this.newThis(fn(this.value))
    }
}


class OtherMappable<A> extends Mappable<A> {
    newThis<B>(b: B) {
        return new OtherMappable<B>(b)
    }

    getValue() {
        return this.value
    }
}

console.log(
    new OtherMappable(3)
        .map<number, OtherMappable>((a) => a + 1)
        .getValue()
)

whereas, without, you have to follow a pattern like this:

interface HKT {
  input: unknown,
  output: unknown
}

type CallHKT<F extends HKT, I> =
  (F & { input: I })["output"]


interface MappableHKT extends HKT {
    output: Mappable<this["input"]>
}

class Mappable<A> {
    constructor(protected value: A) {}

    newThis<B>(b: B) {
        return new Mappable<B>(b)
    }

    map<B, MKT extends MappableHKT>(fn: (a: A) => B): CallHKT<MKT, B> {
        return this.newThis(fn(this.value))
    }
}

interface OtherMappableHKT extends MappableHKT {
    output: OtherMappable<this["input"]>
}

class OtherMappable<A> extends Mappable<A> {
    newThis<B>(b: B) {
        return new OtherMappable<B>(b)
    }

    getValue() {
        return this.value
    }
}

console.log(
    new OtherMappable(3)
        .map<number, OtherMappableHKT>((a) => a + 1)
        .getValue()
)
@bradzacher
Copy link
Collaborator

IMO I don't think it's worth even talking about TS issues that aren't even planned to be implemented.

There's little reason to consider reserving syntax if TS hasn't even decided upon the syntax or if it's something they will support.

@Caleb-T-Owens
Copy link
Author

Caleb-T-Owens commented Jun 10, 2022

The TS team accepts the idea in general, it is just not deeming it as not a priority for their current development. (see here)

If the goal of this proposal is to form a standard typing syntax for tools like typescript to make use of, isn't discussing syntax like this important? There is a good amount of references to the TS issue asking how to implement data structures that rely on higher level types or waiting for it to be resolved, so I think it should be considered

@bradzacher
Copy link
Collaborator

My point is that it's not had an official, accepted syntax proposal, nor has it had even a vague implementation timeline - it's currently a theoretical addition to the language.

The point of this proposal isn't to consider the scope of all things that might possibly be added to type languages in the future; to do so would be to define a proposal to boil the ocean.
Instead the point is to define a spec for what is currently implemented in the languages as a feasible minimum set of things that should be supported.

There are TS features that are explicitly excluded from this proposal and those that are being culled after initial inclusion as well. Which is why I said that unplanned, not yet officially accepted TS features are really out of scope.

@dpchamps
Copy link
Contributor

dpchamps commented Jul 16, 2022

IMO this kind of request fits into the general request for a more permissive grammar, re: #103 & #122

The proposal (type annotations, not this issue) should be less focused on features that TypeScript supports (current and future) and more focused on a specification for static typecheckers to implement.

That way we're not constrained by the current state of typescript and TS can continue to organically grow.

@trusktr
Copy link

trusktr commented Sep 20, 2023

The issue

describes a more generic type syntax space, (essentially a new form of comment) where arbitrary syntax (with a few limitations) can be used inside of the comments, leaving it up to type systems like TypeScript to decide what their syntax is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants