Взагалі немає обмежень! Коли я почав вивчати теоретико-теоретичну основу для конструкторів типів, ця думка також бентежила мене. Ми доберемось до цього. Але спочатку дозвольте мені вияснити деяку плутанину. Ці дві цитати:
такий функтор може мати як цільову категорію категорію, побудовану за допомогою конструктора типів
і
можна подумати про функторів, які мають будь-яку категорію як ціль функтора, наприклад, категорію всіх типів 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