在分类术语中,FP中的monad是什么?
每当有人承诺要“解释单子”时,我的兴趣就会激化,只有当所谓的“解释”是一个长长的清单时,才会被挫败所取代。想法“在这一点上”太复杂了“。
现在我要求相反。 我对类别理论有着坚实的把握,我不害怕追图,Yoneda的引理或派生的函子(实际上就是在类别意义上的monad和adjunctions)。
有人能给我一个清晰简洁的定义,说明函数式编程中的monad是什么? 例子越less越好:有时一个清晰的概念就是超过一百个胆小的例子。 虽然我不挑剔,但Haskell会很好地作为示范语言。
作为卡尔的回答,哈斯克尔的Monad(理论上)是这样的:
class Monad m where join :: m (ma) -> ma return :: a -> ma fmap :: (a -> b) -> ma -> mb
注意“bind”( >>=
)可以被定义为
x >>= f = join (fmap fx)
根据Haskell Wiki
C类中的monad是一个三元组( F :C→C,η: Id → F ,μ: F → F → F )
…有一些公理。 对于Haskell, fmap
, return
和join
分别与F ,η和μ fmap
。 (Haskell中的fmap
定义了一个Functor)。 如果我没有弄错,Scala会把这些map
分别称为pure
和join
。 (Scala调用绑定“flatMap”)
这个问题有一些很好的答案: 单子作为辅助
更重要的是,Derek Elkins在TMR#13中的“用分类理论计算单子”文章应该有你正在寻找的结构: http : //www.haskell.org/wikiupload/8/85/TMR- Issue13.pdf
最后,也许这是最接近你所寻找的,你可以直接find源,并看看莫吉在这个主题从1988年至91年的开创性论文: http : //www.disi.unige.it/人/ MoggiE / publications.html
特别参见“计算和单子的概念”。
我自己肯定太浓缩/不精确:
从Haskelltypes的对象开始,Haskell的态射是函数。 Hask
函数也是对象,产品也是。 所以Hask
是笛卡儿closures的。 现在引入一个箭头映射Hask
每个对象到MHask
,它是MHask
中对象的一个子集。 单元! 接下来介绍一个箭头映射到Hask
上的每个箭头到Hask
上的箭头。 这给了我们地图,并使MHask
成为共同的内部pipe理者。 现在引入一个箭头映射MHask
中的每个对象,它是从MHask
中的一个对象(通过单元)生成的,生成它的MHask
中的对象。 join! 从这个angular度来说, MHask
是一个monad(更精确的说是monoidal endofunctor)。
我相信有一个原因,为什么上述是不足的,这就是为什么我会真正指导你,如果你正在寻找forms主义,特别是对莫吉纸。
好的,使用Haskell的术语和例子
在函数式编程中,monad是types为* -> *
数据types的组合模式。
class Monad (m :: * -> *) where return :: a -> ma (>>=) :: ma -> (a -> mb) -> mb
(Haskell有更多的类,但这些是重要的部分。)
数据types是一个monad,如果它可以在满足实现中的三个条件的同时实现该接口。 这些是“单子法”,我将把它留给那些长篇大论的解释。 我将这些规律归结为“ (>>= return)
是一个身份函数, (>>=)
是关联的。 即使可以更精确地expression,实际上也不过如此。
这就是一个monad。 如果你可以在保留这些行为属性的同时实现这个接口,那么你有一个monad。
这个解释可能比你想象的要短。 那是因为monad接口真的很抽象。 令人难以置信的抽象层次是为什么如此多的不同事物可以被模拟为单子的一部分。
不太明显的是,像接口一样抽象,它允许一般地build模任何控制stream模式,而不pipe实际的monad实现。 这就是为什么GHC的base
库中的Control.Monad
包含有像forever
这样的组合器的原因。这就是为什么显式抽象任何monad实现的能力是强大的,尤其是在types系统的支持下。
我真的不知道我在说什么,但这是我的意见:
单子用来表示计算。 你可以把一个正常的过程程序看作是一系列组合的计算。 单子是这个概念的概括,允许你定义语句是如何组成的。 每个计算都有一个值(它可能只是()
); monad只是决定了通过一系列计算所产生的值是如何performance的。
标记实际上是明确的:它基本上是一种特殊的基于语句的语言,可以让你定义语句之间发生的事情。 就好像你可以定义如何“;” 工作在C语言。
有鉴于此,我所使用的所有monads都是有意义的: State
不会影响值,但会更新从计算到后台传递的第二个值; 如果它遇到一个Nothing
Maybe
短路的价值; List
让你有一个可变数量的值通过; IO
可以让你以安全的方式传递不纯的值。 像Gen
和Parsecparsing器一样,我使用的更专业的monad也是类似的。
希望这是一个不完全脱离基地的明确的解释。
你应该阅读Eugenio Moggi的“计算和单子概念”这篇文章,这个概念解释了monad当时提出的有效语言指称语义结构的作用。
还有一个相关的问题:
用于学习纯函数语言(如Haskell)背后的理论的参考?
因为你不想挥手,你必须阅读科学论文,而不是论坛的答案或教程。
一个monad是endofunctors类别中的monoid,那么问题是什么? 。
除了幽默之外,我个人也相信,monads在Haskell和函数式编程中的使用,从monad-as-an-interface的angular度(比如在Carl's和Dan的答案中),而不是从monads-从类别理论的angular度来看。 我必须承认,当我不得不在实际项目中使用另一种语言的一元 图书馆时,我才真正内化了整个monad的东西。
你提到你不喜欢所有的“大量的例子”教程。 有没有人指出你的尴尬class纸? 它把注意力集中在IO monad上,但是这个介绍给了Haskell首先接受monad概念的一个很好的技术和历史的解释。
既然你从类别理论的angular度理解单子,我将把你的问题解释为关于function性编程中单子的表示 。 因此,我的回答避免了对monad 是什么的解释,也没有对它的意义或用法的直觉。
答案 :在Haskell中,一个monad以某种types的内部语言呈现为一个Kleisli三元组的(内化的)映射。
说明 :“ Hask
范畴”的属性很难做到精确,而这些属性在很大程度上与理解Haskell的单子表示无关。 相反,对于这个讨论,将Haskell理解为某个C类的内部语言会更有用。 Haskell函数定义了C中的态射,而Haskelltypes是C中的对象,但是这些定义所在的特定类别并不重要。
参数数据types,例如data F a = ...
是对象映射 ,例如F : |
C | -> |
| -> |
C |
。
Haskell中monad的通常描述是在Kleisli三元组 (或Kleisli扩展 )中的forms:
class Monad m where return :: a -> ma (>>=) :: ma -> (a -> mb) -> mb
哪里:
-
m
是对象映射m :|
C| -> |
| -> |
C|
-
return
是对象上的单位操作 -
>>=
(由Haskellers发音为“bind”)是态射的扩展操作,但前两个参数交换(参见扩展名(-)* : (a -> mb) -> ma -> mb
)
(这些映射本身被内化为C中的态射族 ,这可能是因为m :|
C | -> |
C |
)。
哈斯克尔的做法(如果你遇到过这个问题)是克莱斯里类别的内部语言。
Haskell的wikibook页面有一个很好的基本解释。