TypeScript Academy · Lektion

Det lättviktiga HKT-mönstret

Implementera tricket med avfunktionalisering av Kind/URI.

Lektion 3 av 413 steg

Det lättviktiga HKT-mönstret är en gratis lektion i TypeScript Academy på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för TypeScript Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i TypeScript Academy innehåller totalt 4 lektioner.

Defunktionalisering

Tricket bakom kodningen har ett namn: defunktionalisering. I stället för en verklig typfunktion av högre ordning representerar vi varje funktion med en tagg och löser upp den med en enda förstahandsuppslagning. Registret URItoKind är denna uppslagstabell.

type Kind<F extends URIS, A> = URItoKind<A>[F];
// One lookup replaces true type-function application

Kind-typen

Kind<F, A> är mönstrets offentliga gränssnitt. Läs det som "konstruktorn F tillämpad på A". Det döljer registerindexeringen bakom ett tydligt namn.

type A = Kind<"Array", number>;  // number[]
type B = Kind<"Option", string>; // string | null

Begränsa F till URIS

F måste vara en registrerad URI. Begränsa den med extends URIS så att endast giltiga taggar kan användas och stavfel blir kompileringsfel.

type Kind<F extends URIS, A> = URItoKind<A>[F];

// Kind<"Arrey", number> -> error, not a valid URI

Skriva generiska signaturer

Nu kan vi skriva den tidigare omöjliga Functor-signaturen. Ersätt varje F<A> med Kind<F, A>, så godkänner kompilatorn den.

interface Functor<F extends URIS> {
  map<A, B>(fa: Kind<F, A>, f: (a: A) => B): Kind<F, B>;
}

Upplösning i praktiken

När ni låser F till en konkret URI löses Kind upp till den verkliga behållartypen. En Functor<"Array"> har en map från A[] till B[].

type ArrayFunctor = Functor<"Array">;
// map: <A, B>(fa: A[], f: (a: A) => B) => B[]

Flera typargument

Vissa konstruktorer tar två argument, som Either<E, A>. fp-ts utökar mönstret med URItoKind2 och Kind2<F, E, A> för kind * -> * -> *. Idén kan skalas genom att fler register läggs till.

interface URItoKind2<E, A> {
  Either: { left: E } | { right: A };
}
type Kind2<F extends URIS2, E, A> = URItoKind2<E, A>[F];

fp-ts-konventionen

fp-ts etablerade den konvention som hela kursen följer: en URI-sträng per datatyp, ett URItoKind-register som utökas genom deklarationssammanslagning och Kind för upplösning. När ni känner igen den kan ni läsa typ-signaturer i fp-ts och Effect.

// In fp-ts you will see exactly:
// declare module "fp-ts/HKT" { interface URItoKind<A> { ... } }

En instanspost

En "instans" av en abstraktion är ett värde som implementerar den för en specifik URI. Instansen innehåller den konkreta map-funktionen. Nästa lektion skriver vi Array-instansen; här ser ni dess struktur.

declare const arrayFunctor: Functor<"Array">;
const out = arrayFunctor.map([1, 2, 3], n => n * 2); // number[]

Varför detta är "lättviktigt"

Det kallas mönstret för lättviktiga HKT:er eftersom det inte kräver några kompilatorändringar eller någon särskild syntax, utan bara gränssnitt och indexerad åtkomst. Kostnaden är en viss ceremoni (URI:er och register) i utbyte mot genuint behållargenerisk kod.

type Kind<F extends URIS, A> = URItoKind<A>[F];
// No magic, just a typed lookup table

Begränsningar

Mönstret är omständligt och felmeddelanden kan vara kryptiska eftersom de nämner kodningen i stället för er domän. Det kräver också att varje behållare registreras. I de flesta appar använder ni bibliotek som redan gör detta i stället för att bygga det själva.

// Trade-off: real abstraction power vs. encoding ceremony

Så hänger det ihop

Det fullständiga receptet för lättviktiga HKT:er är: definiera en URI, registrera den i URItoKind, definiera abstraktioner med Kind<F, A> och tillhandahålla instanser per URI. Det är hela verktygslådan bakom generiska funktionella bibliotek i TypeScript.

type Kind<F extends URIS, A> = URItoKind<A>[F];
interface Functor<F extends URIS> {
  map<A, B>(fa: Kind<F, A>, f: (a: A) => B): Kind<F, B>;
}

Snabbkontroll

Testa er förståelse av mönstret för lättviktiga HKT:er.

Sammanfattning

Ni har satt ihop mönstret för lättviktiga HKT:er.

  • Defunktionalisering ersätter tillämpning av typfunktioner med en uppslagning.
  • Kind<F, A> löser upp en URI plus ett argument till en konkret typ.
  • Generiska signaturer använder Kind i stället för F<A>.
  • Mönstret kan utökas till två argument via Kind2 och följer fp-ts-konventionen.

Nästa steg: en generisk map med verkliga instanser.

Gratis att börja

Lär dig TypeScript med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
101
Lektioner
352

Vanliga frågor

Är lektionen ”Det lättviktiga HKT-mönstret” gratis?

Ja – hela texten till ”Det lättviktiga HKT-mönstret” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i TypeScript Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i TypeScript Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Det lättviktiga HKT-mönstret”?

Implementera tricket med avfunktionalisering av Kind/URI. Ni övar på TypeScript Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig TypeScript Academy?

Du behöver inga förkunskaper. Utbildningen i TypeScript Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.

Hur lång tid tar lektionen ”Det lättviktiga HKT-mönstret”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här TypeScript Academy-lektionen?

Ja. Varje TypeScript Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. HKT-problemet i TypeScript
  2. Definiera typkonstruktorer
  3. Det lättviktiga HKT-mönstret
  4. Generiska funktorer och mappare
← Tillbaka till TypeScript Academy