Я прийшов на цю посаду шляхом кращого розуміння висновку сумнозвісної цитати з Теорії категорій Мака Лейн для працюючого математика .
Описуючи, що щось таке, часто так само корисно описувати те, що це не так.
Той факт, що Mac Lane використовує опис для опису монади, може означати, що він описує щось унікальне для монад. Ведміть мене. Щоб розвинути більш широке розуміння твердження, я вважаю, що йому слід чітко пояснити, що він не є описує те, що є унікальним для монад; у заяві однаково описуються додаткові та стрілки серед інших. З тієї ж причини ми можемо мати два моноїди на Int (сума та продукт), у нас може бути декілька моноїдів на X у категорії ендофункторів. Але подібності є ще більше.
І Monad, і Applicative відповідають критеріям:
У операторі використовується "Категорія ...". Це визначає сферу твердження. Як приклад, категорія Functor описує сферу дії f * -> g *
, тобто Any functor -> Any functor
, наприклад, Tree * -> List *
абоTree * -> Tree *
.
Що категоричне твердження не вказує, описує, де все і все дозволено .
У цьому випадку всередині функторів * -> *
ака a -> b
не вказується, що означає Anything -> Anything including Anything else
. Коли моя фантазія стрибає до Int -> String, вона також включає Integer -> Maybe Int
або навіть Maybe Double -> Either String Int
куди a :: Maybe Double; b :: Either String Int
.
Отже, твердження складається разом так:
- область функтора
:: f a -> g b
(тобто будь-який параметризований тип до будь-якого параметру)
- ендо + функтор
:: f a -> f b
(тобто будь-який один параметризований тип до того ж параметризованого типу) ... сказано по-різному,
- моноїд у категорії ендофункторів
Отже, звідки сила цієї конструкції? Щоб оцінити повну динаміку, мені потрібно було зрозуміти, що типові малюнки моноїда (єдиного об’єкта з тим, що схоже на стрілку ідентичності, :: single object -> single object
) не ілюструють, що мені дозволяється використовувати стрілку, параметризовану на будь-яку кількість моноїдних значень, від об'єкта одного типу, дозволеного в Monoid. Визначення еквівалентності стрілки endo, ~ ідентичності ігнорує значення типу функтора, а також тип і значення самого внутрішнього шару "корисного навантаження". Таким чином, еквівалентність повертається true
в будь-якій ситуації, коли функціональні типи збігаються (наприклад, Nothing -> Just * -> Nothing
еквівалентні Just * -> Just * -> Just *
тому, що вони обидва Maybe -> Maybe -> Maybe
).
Бічна панель: ~ зовні є концептуальною, але є найбільш лівим символом у f a
. Він також описує, що читає "Haskell" спочатку (велика картина); тож тип "зовні" стосовно значення типу. Взаємозв'язок між шарами (ланцюжком посилань) у програмуванні непросто пов'язати у категорії. Категорія набору використовується для опису типів (Int, Strings, можливо Int тощо), що включає категорію Functor (параметризовані типи). Опорний ланцюг: Тип функціонера, Значення функціоналу (елементи набору цього функтора, наприклад, Нічого, Просто), і, в свою чергу, все інше, на яке вказує значення кожного функтора. У категорії відносини описуються по-різному, наприклад, return :: a -> m a
вважається природним перетворенням від одного Функтора до Іншого Функтора, відмінним від усього, що згадувалося до цього часу.
Повертаючись до основної нитки, в цілому для будь-якого визначеного тензорного добутку та нейтрального значення, заява закінчується описом дивовижно потужної обчислювальної конструкції, народженої з його парадоксальної структури:
- зовні він постає як єдиний об'єкт (наприклад,
:: List
); статичний
- але всередині, дозволяє багато динаміки
- будь-яка кількість значень того ж типу (наприклад, Empty | ~ NonEmpty), що є кормом для функцій будь-якої арії. Продукт тензора зменшить будь-яку кількість входів до одного значення ... для зовнішнього шару (~
fold
що нічого не говорить про корисне навантаження)
- нескінченний діапазон як типу, так і значень для самого внутрішнього шару
У Хаскеллі важливим є уточнення застосовності твердження. Потужність і універсальність цієї конструкції, не має абсолютно нічого спільного з монадой по собі . Іншими словами, конструкція не покладається на те, що робить монаду унікальною.
Намагаючись розібратися, чи потрібно будувати код із спільним контекстом для підтримки обчислень, які залежать один від одного, порівняно з обчисленнями, які можна виконувати паралельно, це сумнозвісне твердження, настільки, наскільки воно описує, не є контрастом між вибором Додаток, стрілки та монади, а це опис того, наскільки вони однакові. Що стосується рішення, заява суперечлива.
Це часто неправильно розуміється. Твердження далі описується join :: m (m a) -> m a
як тензорний добуток для моноїдного ендофунктора. Однак це не чітко визначає, як у контексті цього твердження (<*>)
також можна було вибрати. Це справді є прикладом шести / півдюжини. Логіка поєднання значень точно однакова; один і той же вхід генерує однаковий вихід з кожного (на відміну від моноїдів Sum та Product для Int, оскільки вони створюють різні результати при поєднанні Ints).
Отже, підводячи підсумки: Моноїд у категорії ендофайнерів описує:
~t :: m * -> m * -> m *
and a neutral value for m *
(<*>)
і (>>=)
обидва забезпечують одночасний доступ до двох m
значень, щоб обчислити єдине повернене значення. Логіка, яка використовується для обчислення повернутого значення, точно така ж. Якби не різні форми функцій, які вони параметризують ( f :: a -> b
проти k :: a -> m b
) та положення параметра з тим самим типом повернення обчислення (тобто a -> b -> b
проти b -> a -> b
кожної відповідно), я підозрюю, що ми могли б параметризувати моноїдну логіку, тензорний добуток для повторного використання в обох визначеннях. Як вправу зробити точку, спробуйте виконати ~t
, і ви закінчите (<*>)
і (>>=)
залежно від того, як ви вирішите це визначити forall a b
.
Якщо мій останній пункт є як мінімум концептуально правдивим, то він пояснює точну та єдину обчислювальну різницю між додатком та монадою: функції, які вони параметризують. Іншими словами, різниця є зовнішньою для реалізації класів цих типів.
На закінчення, на моєму власному досвіді, сумнозвісна цитата Мак-Лейн забезпечила чудовий мемо «гото», який я можу посилатись, перебуваючи в дорозі по категорії, щоб краще зрозуміти ідіоми, які використовуються в Haskell. Йому вдалося захопити сферу потужної обчислювальної спроможності, яка стала чудово доступною в Haskell.
Однак є іронія в тому, як я вперше неправильно зрозумів застосовність твердження поза монадою, і те, що я сподіваюсь, передано тут. Все, що він описує, виявляється подібним між Applicative та Monads (і Стрілками серед інших). Те, що вона не говорить, - це саме невелика, але корисна відмінність між ними.
- Е