Оскільки ніхто більше не відповів на це питання, я думаю, я сам підкажу. Мені доведеться трохи по-філософськи.
Узагальнене програмування - це абстрагування подібних типів без втрати інформації про тип (що відбувається з поліморфізмом об'єктно-орієнтованого значення). Для цього типи обов'язково повинні мати спільний інтерфейс (набір операцій, а не термін ОО), який ви можете використовувати.
В об'єктно-орієнтованих мовах типи задовольняють інтерфейс завдяки класам. У кожного класу є власний інтерфейс, визначений як частина його типу. Оскільки всі класи 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
само, як і в об'єктно-орієнтованих мовах, ви могли б встановити обмеження успадкування. Ну, начебто.
Підсумовуючи речі, ваша здатність використовувати типи вищого роду залежить від вашої здатності обмежувати їх або використовувати їх як частину обмежень типу.