Generyczne funktory i mapery
Pisz funkcje map ogólne dla dowolnego kontenera
Generyczne funktory i mapery to bezpłatna lekcja TypeScript Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej TypeScript Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs TypeScript Academy zawiera 4 lekcji w sumie.
Generyczny funktor
Teraz wykorzystamy kodowanie zgodnie z jego przeznaczeniem: utworzymy generyczne map, które działa na każdym zarejestrowanym kontenerze. Interfejs Functor, sparametryzowany przez URI, deklaruje jedną metodę.
interface Functor<F extends URIS> {
readonly URI: F;
map<A, B>(fa: Kind<F, A>, f: (a: A) => B): Kind<F, B>;
}Instancja Array
Instancja implementuje map dla jednego URI. Instancja Array mapuje elementy za pomocą wbudowanej metody tablicowej. Jej Kind<"Array", A> rozstrzyga się do A[].
const arrayFunctor: Functor<"Array"> = {
URI: "Array",
map: (fa, f) => fa.map(f)
};Używanie instancji Array
Wywołanie map na instancji Array przekształca każdy element, zachowując typ kontenera tablicy.
const doubled = arrayFunctor.map([1, 2, 3], n => n * 2);
// doubled: number[] -> [2, 4, 6]Typ Option
Zdefiniujmy Option jako wartość albo null i zarejestrujmy go. Jego map stosuje funkcję tylko wtedy, gdy wartość jest obecna; w przeciwnym razie przekazuje dalej null.
interface URItoKind<A> { Option: A | null }
type Option<A> = A | null;Instancja Option
Instancja Option zachowuje kontener opcji: funkcja jest stosowana do wartości, a null pozostaje null.
const optionFunctor: Functor<"Option"> = {
URI: "Option",
map: (fa, f) => (fa === null ? null : f(fa))
};Używanie instancji Option
Ten sam kształt map działa teraz na zupełnie innym kontenerze. Obecne wartości są przekształcane, a nieobecne pozostają bez zmian.
const a = optionFunctor.map(5, n => n + 1); // 6
const b = optionFunctor.map(null, n => n + 1); // nullJedna abstrakcja, wiele kontenerów
Na tym polega korzyść. arrayFunctor i optionFunctor współdzielą ten sam interfejs Functor. Kod napisany dla Functor<F> działa w obu przypadkach bez zmian.
function bumpAll<F extends URIS>(
F: Functor<F>,
fa: Kind<F, number>
): Kind<F, number> {
return F.map(fa, n => n + 1);
}Wywoływanie funkcji generycznej
bumpAll nie wie i nie musi wiedzieć, jaki kontener otrzymuje. Należy przekazać instancję i dane; wynik zachowa typ kontenera.
const arr = bumpAll(arrayFunctor, [1, 2]); // number[] -> [2, 3]
const opt = bumpAll(optionFunctor, 9); // number | null -> 10Prawa funktora
Poprawny funktor przestrzega dwóch praw: mapowanie funkcją identycznościową niczego nie zmienia, a mapowanie dwiema funkcjami po kolei jest równoważne mapowaniu ich złożeniem. Obie przedstawione wcześniej instancje, Array i Option, spełniają te prawa.
// map(fa, x => x) === fa
// map(map(fa, f), g) === map(fa, x => g(f(x)))Dodawanie kolejnych instancji
Ponieważ abstrakcja jest otwarta, nowe kontenery można podłączać przez zarejestrowanie URI i udostępnienie instancji. Tree, Result, Task — każdy z nich może być mapowany przez ten sam generyczny kod.
// Register URI, implement Functor<"Tree">,
// and bumpAll works on trees too - no edits to bumpAllDlaczego ma to znaczenie
Generyczne funktory są punktem wejścia do abstrakcji funkcyjnych w TypeScript: aplikatywów, monad i trawersali. Każda z nich jest interfejsem nad Kind<F, A> z instancjami dla poszczególnych kontenerów. Znają już Państwo mechanizm, dzięki któremu działają fp-ts i Effect.
interface Monad<F extends URIS> extends Functor<F> {
of<A>(a: A): Kind<F, A>;
chain<A, B>(fa: Kind<F, A>, f: (a: A) => Kind<F, B>): Kind<F, B>;
}Szybki test
Proszę sprawdzić zrozumienie generycznych funktorów.
Podsumowanie
Napisali Państwo map działające generycznie na kontenerach.
Functor<F>deklarujemapdziałające naKind<F, A>.- Instancje Array i Option implementują je dla swoich URI.
- Generyczny kod, taki jak
bumpAll, działa dla każdego zarejestrowanego kontenera. - Prawa funktora zapewniają poprawne zachowanie instancji, a bogatsze abstrakcje buduje się na tej podstawie.
Następnie, w kursie 24: tworzenie bezpiecznych typowo parserów.
Ucz się TypeScript dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 101
- Lekcje
- 352
Często zadawane pytania
Czy lekcja „Generyczne funktory i mapery” jest bezpłatna?
Tak — pełny tekst „Generyczne funktory i mapery” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu TypeScript Academy, przejdź na CoddyKit PRO. Kurs TypeScript Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Generyczne funktory i mapery”?
Pisz funkcje map ogólne dla dowolnego kontenera Ćwiczysz TypeScript Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć TypeScript Academy?
Nie wymagamy żadnego doświadczenia. TypeScript Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Generyczne funktory i mapery”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji TypeScript Academy?
Tak. Każda lekcja TypeScript Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Problem HKT w TypeScript
- Definiowanie konstruktorów typów
- Lekki wzorzec HKT
- Generyczne funktory i mapery