Простые примеры для иллюстрации категории, моноида и монады?

Я очень путаюсь с этими тремя понятиями.

есть ли простые примеры, чтобы проиллюстрировать различия между Категория, моноид и Монада ?

было бы очень полезно, если есть иллюстрации этих абстрактных понятий.

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.

(я думаю, что буду редактировать этот пост много, прежде чем это будет иметь смысл..)