Оскільки ніхто більше не відповів на це питання, я думаю, я сам підкажу. Мені доведеться трохи по-філософськи.
Узагальнене програмування - це абстрагування подібних типів без втрати інформації про тип (що відбувається з поліморфізмом об'єктно-орієнтованого значення). Для цього типи обов'язково повинні мати спільний інтерфейс (набір операцій, а не термін ОО), який ви можете використовувати.
В об'єктно-орієнтованих мовах типи задовольняють інтерфейс завдяки класам. У кожного класу є власний інтерфейс, визначений як частина його типу. Оскільки всі класи List<T>мають один і той же інтерфейс, ви можете писати код, який працює незалежно від обраного Tвами. Ще один спосіб нав'язування інтерфейсу - це обмеження спадкування, і хоча ці два здаються різними, вони наче подібні, якщо задуматися.
У більшості об'єктно-орієнтованих мов List<>не є власне типом. Він не має методів і, отже, не має інтерфейсу. Тільки List<T>такі речі мають. По суті, в більш технічному плані єдині типи, на які ви можете змістовно абстрагуватися, - це ті, хто має такий вид *. Щоб використовувати типи вищого роду в об'єктно-орієнтованому світі, вам потрібно формулювати обмеження типу таким чином, що відповідає цьому обмеженню.
Наприклад, як згадується в коментарях, ми можемо розглядати Option<>і List<>як "відображувану", в тому сенсі, що якщо у вас є функція, ви могли б перетворити " Option<T>в" Option<S>або " List<T>в" List<S>. Пам'ятаючи, що класи не можна використовувати для абстрактного вищого типу безпосередньо, ми замість цього робимо інтерфейс:
IMappable<K<_>, T> where K<T> : IMappable<K<_>, T>
А потім ми реалізуємо інтерфейс List<T>і Option<T>в IMappable<List<_>, T>і як і IMappable<Option<_>, T>відповідно. Що ми зробили, це використання типів вищого роду для розміщення обмежень на фактичні (не вищі) типи Option<T>та List<T>. Так робиться в Scala, хоча, звичайно, Scala має такі функції, як ознаки, змінні типу та неявні параметри, які роблять її більш виразною.
В інших мовах можна абстрагуватися над вищими типами безпосередньо. У Haskell, одному з найвищих авторитетів систем типів, ми можемо викласти клас типу для будь-якого типу, навіть якщо він має вищий тип. Наприклад,
class Mappable mp where
map :: mp a -> mp b
Це обмеження, розміщене безпосередньо на (неуточненому) типі, mpякий приймає параметр одного типу, і вимагає, щоб воно було пов'язане з функцією, mapяка перетворюється mp<a>на "an" mp<b>. Тоді ми можемо записати функції, які обмежують типи вищого роду так Mappableсамо, як і в об'єктно-орієнтованих мовах, ви могли б встановити обмеження успадкування. Ну, начебто.
Підсумовуючи речі, ваша здатність використовувати типи вищого роду залежить від вашої здатності обмежувати їх або використовувати їх як частину обмежень типу.