Простые примеры для иллюстрации категории, моноида и монады?
Я очень путаюсь с этими тремя понятиями.
есть ли простые примеры, чтобы проиллюстрировать различия между Категория, моноид и Монада ?
было бы очень полезно, если есть иллюстрации этих абстрактных понятий.
1 ответов
это не ответ, который вы ищете, но здесь вы идете в любом случае:
действительно кривой способ смотреть на монады & co.
один из способов взглянуть на абстрактные понятия, как это, чтобы связать их с основными понятиями, такими как обычные операции обработки списка. Тогда, можно сказать, что
- категория обобщает
(.)операции. - моноид обобщает
(++)операции. - A функтор обобщает
mapоперации. - прикладной функтор обобщает
zip(илиzipWithоперации). - монада обобщает
concatоперации.
В Категории
категория состоит из набора (или класса) объектов и пучка стрелок, каждый из которых соединяет два объекта. Кроме того, для каждого объекта должна быть стрелка идентификации, соединяющая этот объект с самим собой. Далее, если есть одна стрелка (f), который заканчивается на объекте, а другой (g), который начинается с того же объекта, тогда также должна быть составная стрелка под названием g . f.
в Haskell это моделируется как класс, который представляет категорию типов Haskell как объекты.
class Category cat where
id :: cat a a
(.) :: cat b c -> cat a b -> cat a c
основными примерами категории являются функции. Каждая функция соединяет два типа, для всех типов существует функция id :: a -> a который соединяет тип (и значение) с самим собой. Состав функции-это обычный функциональный состав.
короче говоря, категории в базе Haskell-это вещи, которые ведут себя как функции, т. е. вы можете поставить один за другим с обобщенной версией (.).
Моноидом
моноид-это множество с единичным элементом и ассоциативной операцией. Это моделируется в Haskell, как:
class Monoid a where
mempty :: a
mappend :: a -> a -> a
общие примеры моноидов включают в себя:
- набор чисел, элемент 0 и операция
(+). - набор натуральных чисел, элемент 1 и операция
(*). - набор всех списков, пустой список
[]операция(++).
они смоделированы в Haskell как
newtype Sum a = Sum {getSum :: a}
instance (Num a) => Monoid (Sum a) where
mempty = Sum 0
mappend (Sum a) (Sum b) = Sum (a + b)
instance Monoid [a] where
mempty = []
mappend = (++)
моноиды используются для "объединения" и накопления вещей. Например, функция mconcat :: Monoid a => [a] -> a, может использоваться для уменьшения списка сумм до одной суммы или вложенного списка в плоский список. Рассматривайте это как своего рода обобщение (++) или (+) операции, которые в некотором роде "сливают" две вещи.
Функтор
функтор в Haskell-это вещь, которая прямо обобщает операцию map :: (a->b) -> [a] -> [b]. Вместо отображения по списку он отображает некоторые структура, например, список, двоичное дерево или даже операция ввода-вывода. Функторы моделируются следующим образом:
class Functor f where
fmap :: (a->b) -> f a -> f b
сравните это с определением нормальных .
Прикладной Функтор
аппликативные функторы можно рассматривать как вещи с генерализованной zipWith операции. Функторы отображают общие структуры по одному в то время, но с помощью прикладного функтора вы можете zip вместе две или более структур. Для простейшего примера вы можете использовать аппликаторы для zip вместе два целых числа внутри Maybe тип:
pure (+) <*> Just 1 <*> Just 2 -- gives Just 3
обратите внимание, что структура может повлиять на результат, для пример:
pure (+) <*> Nothing <*> Just 2 -- gives Nothing
сравните это с обычным zipWith функция:
zipWith (+) [1] [2]
вместо просто списков, аппликативные работы для всех видов структур. Кроме того, умный трюк с pure и (<*>) обобщает сжатие для работы с любым количеством аргументов. Чтобы увидеть, как это работает, проверьте следующие типы, сохраняя концепцию частично применяемых функций под рукой:
instance (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
обратите внимание также на сходство между fmap и (<*>).
Монаду
монады часто используется для моделирования различных вычислительных контекстов, таких как недетерминированные, или effectful вычислений. Поскольку уже слишком много учебников монады, я просто рекомендую лучший, вместо того, чтобы писать еще один.
что касается обычных функций обработки списка, монады обобщают функцию concat :: [[a]] -> [a] работать с много других видов структур кроме списков. В качестве простого примера, монадическая операция join может использоваться для сглаживания вложенных Maybe значения:
join (Just (Just 42)) -- gives Just 42
join (Just (Nothing)) -- gives Nothing
как это связано с использованием монад в качестве средства структурирования вычислений? Рассмотрим пример игрушки, где вы делаете два последовательных запроса из некоторой базы данных. Первый запрос возвращает вам некоторое значение ключа, с которым вы хотите выполнить другой поиск. Проблема здесь в том, что первое значение обернуто внутри Maybe, поэтому вы не можете запросить с этим непосредственно. Вместо этого, как может быть Functor, вы могли бы вместо fmap возвращаемое значение с новым запросом. Это даст вам два вложенных Maybe значения, как указано выше. Другой запрос приведет к трем уровням Maybes. Это было бы довольно сложно запрограммировать, но монадический join дает вам возможность сгладить эту структуру и работать только с одним уровнем Maybes.
(я думаю, что буду редактировать этот пост много, прежде чем это будет иметь смысл..)