Взагалі немає обмежень! Коли я почав вивчати теоретико-теоретичну основу для конструкторів типів, ця думка також бентежила мене. Ми доберемось до цього. Але спочатку дозвольте мені вияснити деяку плутанину. Ці дві цитати:
такий функтор може мати як цільову категорію категорію, побудовану за допомогою конструктора типів
і
можна подумати про функторів, які мають будь-яку категорію як ціль функтора, наприклад, категорію всіх типів Haskell
покажіть, що ви нерозумієте, що таке функтор (або, принаймні, ви зловживаєте термінологією).
Функціонери не будують категорії. Функтор - це відображення між категоріями. Функціонери приводять об'єкти та морфізми (типи та функції) у категорію джерела до об'єкта та морфізми в цільовій категорії.
Зауважте, що це означає, що функтор - це дійсно пара відображень: відображення на об'єктах F_obj та відображення на морфізмах F_morph . У Haskell об'єктною частиною F_obj функтора є ім'я конструктора типів (наприклад List
), тоді як частина морфізму - це функція fmap
(саме від компілятора Haskell слід розібратися, до якого fmap
ми маємо на увазі будь-який вираз). Таким чином, ми не можемо сказати, що List
це функтор; тільки комбінація List
і fmap
є функтором. Все-таки люди зловживають позначеннями; програмісти називають List
функтора, тоді як теоретики категорії використовують один і той же символ для позначення обох частин функтора.
Крім того, в програмуванні майже всі функтори є ендофайнерами , тобто категорія джерела та цілі однакові - категорія всіх типів нашої мови. Назвемо цю категорію Тип . Ендофунктор F на Type вказує тип T на інший тип FT і функцію T -> S на іншу функцію FT -> FS . Звичайно, це відображення повинне підкорятися законам функтора.
Використовуючи в List
якості прикладу: у нас є конструктор типу List : Type -> Type
, і функція fmap: (a -> b) -> (List a -> List b)
, що разом утворює функтор. Т
Є ще один заключний момент, який слід прояснити. Запис List int
не створює новий тип списків цілих чисел. Цей тип вже існував . Це був об’єкт у нашій категорії Тип . List Int
це просто спосіб посилатися на це.
Тепер вам цікаво, чому функтор не може відобразити тип, скажімо, Int
або String
. Але, може! Потрібно просто використовувати функцію посвідчення особи. Для будь-якої категорії С функціонер ідентичності відображає кожен об'єкт до себе і морфізм до себе. Нескладно переконатися, що це відображення відповідає законам функтора. У Haskell це буде конструктор типів, id : * -> *
який відображає кожен тип до себе. Наприклад, id int
оцінює до int
.
Крім того, можна навіть створити постійні функтори, які зіставляють всі типи в один тип. Наприклад, функтор ToInt : * -> *
, де ToInt a = int
для всіх типів a
, і відображає всі морфізми до цілої функції ідентичності: fmap f = \x -> x