每当有人承诺“解释monad”时,我的兴趣就会被激怒,只有当被指称的“解释”是一长串的例子后才会被挫败所取代,这些例子被一些副手的评论所终止,即“数学理论”背后的“深奥的想法”“太复杂了,无法解释”。
现在我要求相反的事情。我对类别理论有着扎实的把握,我并不害怕图表追逐,Yoneda的引理或派生的函子(实际上是 monads 和分类意义上的附件)。
有人能给我一个清晰简洁的定义monad在函数式编程中的含义吗?越少越好的例子:有时一个清晰的概念说明了一百多个胆小的例子。尽管我不挑剔,Haskell作为一种演示语言会很好。
答案 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)
C 类别中的monad是三元组( F :C→C,η: Id → F ,μ: F ∘ F → F )
......有些公理。对于Haskell,fmap
,return
和join
分别与 F ,η和μ对齐。 (Haskell中的fmap
定义了一个Functor)。如果我没弄错的话,Scala会分别调用这些map
,pure
和join
。 (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
包具有when
,forever
等组合器的原因。这就是为什么显式抽象任何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有一个很好的基本解释。