Ponieważ nikt inny nie odpowiedział na to pytanie, myślę, że spróbuję. Będę musiał trochę filozofować.
Programowanie ogólne polega na abstrakcji nad podobnymi typami, bez utraty informacji o typie (co dzieje się z polimorfizmem wartości obiektowych). Aby to zrobić, typy muszą koniecznie współdzielić jakiś interfejs (zestaw operacji, a nie termin OO), którego można użyć.
W językach obiektowych typy spełniają interfejs dzięki klasom. Każda klasa ma własny interfejs zdefiniowany jako część swojego typu. Ponieważ wszystkie klasy List<T>mają ten sam interfejs, możesz pisać kod, który działa bez względu na to, co Twybierzesz. Innym sposobem nałożenia interfejsu jest ograniczenie dziedziczenia i chociaż oba wydają się różne, są one trochę podobne, jeśli się nad tym zastanowić.
W większości języków obiektowych List<>sam w sobie nie jest właściwym typem. Nie ma metod, a zatem nie ma interfejsu. Tylko List<T>to ma te rzeczy. Zasadniczo, z bardziej technicznego punktu widzenia, jedynymi typami, które można znacząco wyodrębnić, są te z tym rodzajem *. Aby korzystać z typów lepiej dobranych w świecie zorientowanym obiektowo, musisz sformułować ograniczenia typu w sposób zgodny z tym ograniczeniem.
Na przykład, jak wspomniano w komentarzach, możemy przeglądać Option<>i List<>„mapować”, w tym sensie, że jeśli masz funkcję, możesz przekonwertować Option<T>na an Option<S>lub List<T>na List<S>. Pamiętając, że klasy nie mogą być używane do abstrakcyjnego nad typami wyższego rodzaju, zamiast tego tworzymy interfejs:
IMappable<K<_>, T> where K<T> : IMappable<K<_>, T>
A następnie zaimplementować interfejs zarówno List<T>a Option<T>jak IMappable<List<_>, T>i IMappable<Option<_>, T>odpowiednio. To, co zrobiliśmy, polega na użyciu typów o wyższym rodzaju, aby nałożyć ograniczenia na rzeczywiste typy (o innym rodzaju) Option<T>i List<T>. Tak to się dzieje w Scali, chociaż oczywiście Scala ma takie cechy, jak cechy, zmienne typu i ukryte parametry, które czynią ją bardziej wyrazistą.
W innych językach można bezpośrednio wyodrębnić typy wyższego rodzaju. W Haskell, jednym z najwyższych uprawnień w systemach typów, możemy sformułować klasę typu dla dowolnego typu, nawet jeśli ma on wyższy rodzaj. Na przykład,
class Mappable mp where
map :: mp a -> mp b
Jest to ograniczenie nakładane bezpośrednio na (nieokreślony) typ, mpktóry przyjmuje jeden parametr typu i wymaga, aby był on powiązany z funkcją, mapktóra zmienia an mp<a>w mp<b>. Następnie możemy napisać funkcje ograniczające typy wyższego rzędu, Mappabletak jak w językach zorientowanych obiektowo można wprowadzić ograniczenie dziedziczenia. Cóż, w pewnym sensie.
Podsumowując, twoja umiejętność korzystania z typów o wyższym rodzaju zależy od twojej zdolności do ich ograniczenia lub użycia ich jako części ograniczeń typów.