Что такое монада? - PullRequest
       294

Что такое монада?

1330 голосов
/ 05 сентября 2008

Кратко рассмотрев недавно Хаскелла, каким было бы краткое, краткое, практичное объяснение того, что в сущности является монадой?

Я обнаружил, что большинство объяснений, с которыми я столкнулся, было довольно недоступным и лишено практических деталей.

Ответы [ 45 ]

2 голосов
/ 13 мая 2012

Я тоже пытаюсь понять монады. Это моя версия:

Монады - это создание абстракций о повторяющихся вещах. Во-первых, сама монада является типизированным интерфейсом (как абстрактный обобщенный класс), который имеет две функции: связывание и возврат, которые определяют сигнатуры. И затем мы можем создавать конкретные монады на основе этой абстрактной монады, конечно же, с конкретными реализациями связывания и возврата. Кроме того, связывание и возврат должны выполнять несколько инвариантов, чтобы можно было составлять / связывать бетонные монады.

Зачем создавать концепцию монады, когда у нас есть интерфейсы, типы, классы и другие инструменты для создания абстракций? Потому что монады дают больше: они приводят к переосмыслению проблем таким образом, который позволяет составлять данные без какого-либо шаблона.

2 голосов
/ 04 февраля 2015

Очень простой ответ:

Монады - это абстракция , которые предоставляют интерфейс для инкапсуляции значений, для вычисления новых инкапсулированных значений и для разворачивания инкапсулированного значения.

Что на практике удобно для них, так это то, что предоставляют единый интерфейс для создания типов данных, которые моделируют состояние, но не сохраняют состояние .

Важно понимать, что Monad - это абстракция , то есть абстрактный интерфейс для работы с определенным типом структуры данных. Этот интерфейс затем используется для создания типов данных, которые имеют монадическое поведение.

Вы можете найти очень хорошее и практичное введение в Монады в Ruby, Часть 1: Введение .

2 голосов
/ 03 июня 2009

Принцесса объяснение F # Выражения вычислений помогло мне, хотя я все еще не могу сказать, что я действительно понял.

РЕДАКТИРОВАТЬ : эта серия, объясняющая монады с помощью javascript, - это та, которая «изменила баланс» для меня.

Я думаю, что понимание монад - это то, что подкрадывается к вам. В этом смысле чтение как можно большего количества «учебных пособий» является хорошей идеей, но часто странные вещи (незнакомый язык или синтаксис) мешают вашему мозгу сосредоточиться на главном.

Некоторые вещи, которые мне было трудно понять:

  • Объяснения, основанные на правилах, никогда не работали для меня, потому что большинство практических примеров на самом деле требуют больше , чем просто возврат / связывание.
  • Кроме того, назвать их правилами не помогло. Это скорее случай «есть эти вещи , которые имеют что-то общее, давайте назовем вещи« монады », а биты в общих« правилах »».
  • Return (a -> M<a>) и Bind (M<a> -> (a -> M<b>) -> M<b>) великолепны, но я никогда не мог понять, как Bind мог извлечь a из M<a>, чтобы передать его в a -> M<b>. Я не думаю, что я когда-либо читал (возможно, это очевидно для всех остальных), что обратная сторона Return (M<a> -> a) имеет , чтобы существовать внутри в монаде, это просто не нужно быть разоблаченным.
2 голосов
/ 25 ноября 2013

В Coursera "Принципы реактивного программирования" тренинг - Эрик Майер описывает их как:

"Monads are return types that guide you through the happy path." -Erik Meijer
2 голосов
/ 14 января 2011

Объяснение монад похоже на объяснение операторов потока управления. Представляете, что непрограммист просит вас объяснить их?

Вы можете дать им объяснение, включающее теорию - логическую логику, регистровые значения, указатели, стеки и фреймы. Но это было бы сумасшествием.

Вы могли бы объяснить их с точки зрения синтаксиса. В основном все операторы потока управления в C имеют фигурные скобки, и вы можете различить условие и условный код по их расположению относительно скобок. Это может быть даже безумнее.

Или вы также можете объяснить циклы, если операторы, подпрограммы, подпрограммы и, возможно, сопрограммы.

Монады могут заменить довольно большое количество методов программирования. Существует определенный синтаксис в языках, которые их поддерживают, и некоторые теории о них.

Они также позволяют функциональным программистам использовать императивный код, фактически не допуская его, но это не единственное их использование.

2 голосов
/ 23 апреля 2017

Еще одна попытка объяснить монады, используя только списки Python и функцию map. Я полностью согласен с тем, что это не полное объяснение, но я надеюсь, что оно дойдет до основных понятий.

Я получил это из видео funfunfunction на Monads и в главе «Learn You A Haskell» «Еще несколько монад» . Я очень рекомендую посмотреть видео с интересными функциями.

Очень просто, монады - это объекты, которые имеют функции map и flatMap (bind в Haskell). Есть некоторые дополнительные обязательные свойства , но это основные.

flatMap 'выравнивает' выходные данные карты, для списков это просто объединяет значения списка, например.

concat([[1], [4], [9]]) = [1, 4, 9]

Итак, в Python мы можем очень просто реализовать Monad только с этими двумя функциями:

def flatMap(func, lst):
    return concat(map(func, lst))

def concat(lst):
    return sum(lst, [])

func - любая функция, которая принимает значение и возвращает список, например,

lambda x: [x*x]

Объяснение

Для ясности я создал функцию concat в Python с помощью простой функции , которая суммирует списки, т.е. [] + [1] + [4] + [9] = [1, 4, 9] (у Haskell есть собственный метод concat).

Я предполагаю, что вы знаете, что такое функция map, например ::1010 *

>>> list(map(lambda x: [x*x], [1,2,3]))
[[1], [4], [9]]

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

Теперь мы можем позвонить:

>>> flatMap(lambda x: [x*x], [1,2,3])
[1, 4, 9]

Эта лямбда принимает значение x и помещает его в список. Монада работает с любой функцией, которая переходит от значения к типу монады, поэтому список в этом случае.

Это ваша монада, определенная .

Я думаю, что вопрос о том, почему они полезны, был дан ответ на другие вопросы.

Больше объяснений

Другими примерами, не являющимися списками, являются обещания JavaScript, которые имеют метод then, и потоки JavaScript, которые имеют метод flatMap.

Таким образом, Promises и Streams используют немного другую функцию, которая выравнивает Stream или Promise и возвращает значение изнутри.

Монада списка Haskell имеет следующее определение:

instance Monad [] where  
    return x = [x]  
    xs >>= f = concat (map f xs)  
    fail _ = [] 

т.е. Есть три функции return (не путать с возвратом в большинстве других языков), >>= (flatMap) и fail.

Надеюсь, вы увидите сходство между:

xs >>= f = concat (map f xs)

и

def flatMap(f, xs):
    return concat(map(f, xs))
2 голосов
/ 05 сентября 2008

Монада - это вещь, используемая для инкапсуляции объектов, которые имеют изменяющееся состояние. Чаще всего это встречается в языках, которые в противном случае не позволяют изменять состояние (например, Haskell).

Примером может служить файловый ввод / вывод.

Вы сможете использовать монаду для файлового ввода-вывода, чтобы изолировать изменяющуюся природу состояния только от кода, который использовал монаду. Код внутри Monad может эффективно игнорировать изменяющееся состояние мира за пределами Monad - это значительно упрощает анализ общего эффекта вашей программы.

1 голос
/ 13 мая 2011

http://mikehadlow.blogspot.com/2011/02/monads-in-c-8-video-of-my-ddd9-monad.html

Это видео, которое вы ищете.

Демонстрация в C # проблем с композицией и выравниванием типов, а затем их правильная реализация в C #. В конце он показывает, как тот же код C # выглядит в F # и, наконец, в Haskell.

0 голосов
/ 09 августа 2018

A Monad - это Applicative (т. Е. Что-то, что вы можете поднять двоичный файл, следовательно, " n -ary" - выполняет функции, (1) и добавьте чистые значения в (2) ) Functor (то есть то, что вы можете отобразить более, (3) т.е. поднять унарный функционирует с (3) ) с добавленной способностью сглаживать вложенный тип данных . В Haskell эта операция выравнивания называется join.

Общий (общий, параметрический) тип этой операции:

join  ::  Monad m  =>  m (m a)  ->  m a

для любой монады m (Примечание: все m одинаковы!).

Определенная m монада определяет свою конкретную версию join, работающую для любого типа значения a, "переносимого" монадическими значениями типа m a. Некоторые конкретные типы:

join  ::  [[a]]           -> [a]         -- for lists, or nondeterministic values
join  ::  Maybe (Maybe a) -> Maybe a     -- for Maybe, or optional values
join  ::  IO    (IO    a) -> IO    a     -- for I/O-produced values

Операция join преобразует m -выражение, производящее * m -вычисление a -типа значений в одно объединенное m -вычисление a -типа , Это позволяет объединить шаги вычислений в одно большее вычисление.

Это вычислительное пошаговое объединение оператор "bind" (>>=) просто использует fmap и join вместе, то есть

(ma >>= k)  ==  join (fmap k ma)
{-
  ma        :: m a            -- `m`-computation which produces `a`-type values
  k         ::   a -> m b     --  create new `m`-computation from an `a`-type value
  fmap k ma :: m    ( m b )   -- `m`-computation of `m`-computation of `b`-type values
  (m >>= k) ::        m b     -- `m`-computation which produces `b`-type values
-}

И наоборот, join можно определить с помощью bind, join mma == mma >>= id, где id ma = ma - в зависимости от того, что удобнее для данного типа m.

Для монад, как do-нотация, так и ее эквивалентный код, написанный оператором bind,

    do { x <- mx ; y <- my ; return (f x y) }        --   x :: a   ,   mx :: m a
                                                     --   y :: b   ,   my :: m b
    mx >>= (\x ->                                    -- nested
                my >>= (\y ->                        --  lambda
                             return (f x y) ))       --   functions

можно читать как

сначала «сделать» mx, а когда это будет сделано, получить его «результат» как x и позвольте мне использовать его для «выполнения» чего-то еще.

В данном блоке do каждое из значений справа от обязательной стрелки <- имеет тип m a для некоторого типа a и одну и ту же монаду m во всем блоке do. return - это нейтральное m -вычисление, которое просто выдает чистое значение, которое ему дано, так что объединение любого m -вычисления с ним вообще не меняет это вычисление.


(1) с liftA2 :: Applicative m => (a -> b -> c) -> m a -> m b -> m c

(2) с pure :: Applicative m => a -> m a

(3) с fmap :: Functor m => (a -> b) -> m a -> m b

Есть также эквивалентные методы Монады,

liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
return :: Monad m =>  a            -> m a
liftM  :: Monad m => (a -> b)      -> m a -> m b

Учитывая монаду, другие определения могут быть сделаны как

pure   a       = return a
fmap   f ma    = do { a <- ma ;            return (f a)   }
liftA2 f ma mb = do { a <- ma ; b <- mb  ; return (f a b) }
(ma >>= k)     = do { a <- ma ; b <- k a ; return  b      }
0 голосов
/ 08 мая 2019

Согласно О чем мы говорим, когда говорим о монадах Вопрос не так:

Краткий ответ на вопрос "Что такое монада?" является то, что он является моноидом в категории эндофункторов или что это общий тип данных, снабженный двумя операциями, которые удовлетворяют определенным законам. Это правильно, но это не раскрывает более важную картину. Это потому, что вопрос не так. В этой статье мы стремимся ответить на правильный вопрос: «Что на самом деле говорят авторы, когда говорят о монадах?»

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

...