根据分类术语,FP中的monad是什么?

时间:2011-11-22 02:55:15

标签: haskell functional-programming monads category-theory

每当有人承诺“解释monad”时,我的兴趣就会被激怒,只有当被指称的“解释”是一长串的例子后才会被挫败所取代,这些例子被一些副手的评论所终止,即“数学理论”背后的“深奥的想法”“太复杂了,无法解释”。

现在我要求相反的事情。我对类别理论有着扎实的把握,我并不害怕图表追逐,Yoneda的引理或派生的函子(实际上是 monads 和分类意义上的附件)。

有人能给我一个清晰简洁的定义monad在函数式编程中的含义吗?越少越好的例子:有时一个清晰的概念说明了一百多个胆小的例子。尽管我不挑剔,Haskell作为一种演示语言会很好。

8 个答案:

答案 0 :(得分:31)

这个问题有一些很好的答案:Monads as adjunctions

更重要的是,Derek Elkins在TMR#13中的“使用类别理论计算Monads”一文应该具有您正在寻找的那种结构:http://www.haskell.org/wikiupload/8/85/TMR-Issue13.pdf

最后,也许这真的是最接近你所寻找的东西,你可以直接找到源头,看看Moggi关于这个主题的开创性论文,从1988-91:http://www.disi.unige.it/person/MoggiE/publications.html

特别参见“计算和monad的概念”。


我自己确定太精简/不精确:

从类别Hask开始,其对象是Haskell类型,其态射是函数。函数也是Hask中的对象,产品也是如此。所以Hask是笛卡尔式的。现在介绍一个箭头,将Hask中的每个对象映射到MHask,这是Hask中对象的子集。单元! 接下来介绍一个箭头,将Hask上的每个箭头映射到MHask上的箭头。这为我们提供了地图,并使MHask成为协变的endofunctor。现在引入一个箭头映射MHask中的每个对象,该对象是从MHask中的对象(通过单位)生成到生成它的MHask中的对象。加入!从那时起,MHask是一个monad(更准确地说是一个monoidal endofunctor)。

我确信上述原因是有缺陷的,这就是为什么我真的会指导你,如果你正在寻找形式主义,尤其是Moggi论文。

答案 1 :(得分:17)

作为对Carl的答案的赞美,Haskell中的Monad(理论上)是这样的:

class Monad m where
  join :: m (m a) -> m a
  return :: a -> m a
  fmap :: (a -> b) -> m a -> m b

请注意,“bind”(>>=)可以定义为

x >>= f = join (fmap f x)

根据the Haskell Wiki

  

C 类别中的monad是三元组( F :C→C,η: Id F ,μ: F F F

......有些公理。对于Haskell,fmapreturnjoin分别与 F ,η和μ对齐。 (Haskell中的fmap定义了一个Functor)。如果我没弄错的话,Scala会分别调用这些mappurejoin。 (Scala调用bind“flatMap”)

答案 2 :(得分:12)

好的,使用Haskell术语和示例......

函数式编程中的monad是具有* -> *种类的数据类型的组合模式。

class Monad (m :: * -> *) where
    return :: a -> m a
    (>>=)  :: m a -> (a -> m b) -> m b

(除了Haskell之外,还有更多的课程,但那些是重要的部分。)

如果数据类型在实现中满足三个条件的同时可以实现该接口,则它是monad。这些是“monad法则”,我将把它留给那些冗长的解释,以获得完整的解释。我将这些定律概括为“(>>= return)是一个身份函数,(>>=)是关联的。”它真的不仅仅是那个,即使它可以更精确地表达。

那是所有 monad。如果您可以在保留这些行为属性的同时实现该接口,则可以使用monad。

这个解释可能比你想象的要短。那是因为monad界面真的非常抽象。令人难以置信的抽象层次是为什么许多不同的东西可以被建模为monad的一部分。

不太明显的是,与接口一样抽象,它允许对任何控制流模式进行一般建模,而不管实际的monad实现。这就是为什么GHC的Control.Monad库中的base包具有whenforever等组合器的原因。这就是为什么显式抽象任何monad实现的能力强大的原因,特别是在类型系统的支持下。

答案 3 :(得分:6)

你应该阅读Eugenio Moggi撰写的论文“计算和单子的概念”,它解释了当时提出的monads对有效语言的指称语义结构的作用。

还有一个相关问题:

References for learning the theory behind pure functional languages such as Haskell?

由于你不想挥手,你必须阅读科学论文,而不是论坛答案或教程。

答案 4 :(得分:5)

我真的不知道我在说什么,但这是我的看法:

Monads用于表示计算。您可以将正常的过程程序(基本上是一个语句列表)视为一堆组合计算。 Monads是这个概念的概括,允许您定义语句的组合方式。每个计算都有一个值(它可能只是()); monad只是决定了一系列计算中的值如何表现。

符号实际上是说明这一点:它基本上是一种特殊的基于语句的语言,可以让你定义语句之间发生的事情。就好像你可以定义“;”使用类C语言。

从这个角度来看,到目前为止我使用过的所有monad都有意义:State不会影响值,但会更新第二个值,该值在后台从计算传递到计算; Maybe如果遇到Nothing,则会将该值短路; List允许您传递可变数量的值; IO允许您以安全的方式传递不纯的值。我使用的更专业的monad如Gen和Parsec解析器也类似。

希望这是一个明确的解释,并非完全偏离基础。

答案 5 :(得分:5)

A monad is a monoid in the category of endofunctors, whats the problem?

除了幽默之外,我个人相信monads,因为它们在Haskell和函数式编程中使用,可以从 monads-as-an-interface 点更好地理解。查看(如Carl和Dan的答案),而不是 monads-as-the-term-from-category-theory 的观点。我必须承认,当我不得不在真实项目中使用来自另一种语言的monadic library时,我才真正内化了整个monad事物。

你提到你不喜欢所有的“很多例子”教程。有没有人向你指出Awkward squad论文?它专注于IO monad,但介绍给出了为什么首先被Haskell所接受的monad概念的技术和历史解释。

答案 6 :(得分:4)

由于你理解了类别理论意义上的monad,我将你的问题解释为关于函数式编程中monad的表示。 因此,我的答案避免了对monad 是什么的任何解释,或对其含义或用途的任何直觉。

答案:在Haskell中,monad以某种类别的内部语言呈现为Kleisli三元组的(内化)地图。

<强>解释: 关于“Hask类别”的属性很难确切,这些属性在很大程度上与理解Haskell的monad表示无关。 相反,对于此讨论,将Haskell理解为某些类别 C 内部语言更为有用。 Haskell函数定义 C 中的态射,Haskell类型是 C 中的对象,但制作这些定义的特定类别并不重要。

参数数据类型,例如data F a = ...对象映射,例如F : | <强> C | -> | <强> C |

Haskell中monad的常用描述是 Kleisli triple (或 Kleisli扩展)形式:

class Monad m where
    return :: a -> m a
    (>>=) :: m a -> (a -> m b) -> m b

其中:

  • m对象映射 m :| C | -> | C |
  • return是对象
  • 上的单元操作
  • >>=(由Haskellers发音为“bind”)是对态射的扩展操作,但是它的前两个参数被交换(参见扩展名(-)* : (a -> m b) -> m a -> m b的常用签名)< / LI>

(这些地图本身内化作为 C 中态射的系列,这可能是m :| C | -> | <强> C |)。

Haskell的执行 - 注释(如果您遇到过这种情况)因此是Kleisli类别的内部语言。

答案 7 :(得分:2)

Haskell wikibook page有一个很好的基本解释。