Det lättviktiga HKT-mönstret
Implementera tricket med avfunktionalisering av Kind/URI.
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 applicationKind-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 | nullBegrä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 URISkriva 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 tableBegrä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 ceremonySå 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
Kindi stället förF<A>. - Mönstret kan utökas till två argument via
Kind2och följer fp-ts-konventionen.
Nästa steg: en generisk map med verkliga instanser.
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
- HKT-problemet i TypeScript
- Definiera typkonstruktorer
- Det lättviktiga HKT-mönstret
- Generiska funktorer och mappare