从分类角度来说,FP 中的 monad 是什么?

发布于 2024-12-17 11:25:41 字数 290 浏览 2 评论 0原文

每当有人承诺“解释单子”时,我的兴趣就会被激起,但当所谓的“解释”是一长串例子时,我的兴趣就会被挫败感所取代,最后是一些即兴的评论,即“深奥的数学理论”背后的“数学理论”。想法”“目前太复杂,无法解释”。

现在我要求相反。我对范畴论有扎实的掌握,而且我不害怕图表追逐、米田引理或派生函子(实际上也包括范畴意义上的单子和附加词)。

有人能给我一个关于函数式编程中 monad 的清晰而简洁的定义吗?例子越少越好:有时一个清晰的概念可以表达一百多个胆怯的例子。尽管我并不挑剔,但 Haskell 作为演示语言会做得很好。

Every time someone promises to "explain monads", my interest is piqued, only to be replaced by frustration when the alleged "explanation" is a long list of examples terminated by some off-hand remark that the "mathematical theory" behind the "esoteric ideas" is "too complicated to explain at this point".

Now I'm asking for the opposite. I have a solid grasp on category theory and I'm not afraid of diagram chasing, Yoneda's lemma or derived functors (and indeed on monads and adjunctions in the categorical sense).

Could someone give me a clear and concise definition of what a monad is in functional programming? The fewer examples the better: sometimes one clear concept says more than a hundred timid examples. Haskell would do nicely as a language for demonstration though I'm not picky.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

还给你自由 2024-12-24 11:25:41

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

更重要的是,Derek Elkins 的“Calculate Monads with TMR #13 中的范畴论”文章应该具有您正在寻找的结构:http://www.haskell.org/wikiupload/8/85/TMR- Issue13.pdf

最后,也许这确实是最接近您正在寻找的内容,您可以直接转到源代码并查看 Moggi 关于该主题的开创性论文: 1988-91:http://www.disi.unige.it/person/ MoggiE/publications.html

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


我自己的观点我确信过于简洁/不精确:

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

我确信上述内容存在缺陷是有原因的,这就是为什么我会特别引导您(如果您正在寻找形式主义)特别是 Moggi 论文。

This question has some good answers: Monads as adjunctions

More to the point, Derek Elkins' "Calculating Monads with Category Theory" article in TMR #13 should have the sort of constructions you're looking for: http://www.haskell.org/wikiupload/8/85/TMR-Issue13.pdf

Finally, and perhaps this is really the closest to what you're looking for, you can go straight to the source and look at Moggi's seminal papers on the topic from 1988-91: http://www.disi.unige.it/person/MoggiE/publications.html

See in particular "Notions of computation and monads".


My own I'm sure too condensed/imprecise take:

Begin with a category Hask whose objects are Haskell types, and whose morphisms are functions. Functions are also objects in Hask, as are products. So Hask is Cartesian closed. Now introduce an arrow mapping every object in Hask to MHask which is a subset of the objects in Hask. Unit!
Next introduce an arrow mapping every arrow on Hask to an arrow on MHask. This gives us map, and makes MHask a covariant endofunctor. Now introduce an arrow mapping every object in MHask which is generated from an object in MHask (via unit) to the object in MHask which generates it. Join! And from the that, MHask is a monad (and a monoidal endofunctor to be more precise).

I'm sure there is a reason why the above is deficient, which is why I'd really direct you, if you're looking for formalism, to the Moggi papers in particular.

横笛休吹塞上声 2024-12-24 11:25:41

作为对 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)

根据 Haskell Wiki

类别中的单子C是一个三元组(F:C→C,η:IdF, μ : FFF)


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

As a compliment to Carl's answer, a Monad in Haskell is (theoretically) this:

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

Note that "bind" (>>=) can be defined as

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

According to the Haskell Wiki

A monad in a category C is a triple (F : C → C, η : IdF, μ : FFF)

...with some axioms. For Haskell, fmap, return, and join line up with F, η, and μ, respectively. (fmap in Haskell defines a Functor). If I'm not mistaken, Scala calls these map, pure, and join respectively. (Scala calls bind "flatMap")

且行且努力 2024-12-24 11:25:41

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

在函数式编程中,单子是一种数据类型的组合模式,其类型为 * ->; *。

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

(该类比 Haskell 中的类有更多内容,但这些是重要的部分。)

如果数据类型可以实现该接口,同时满足实现中的三个条件,则该数据类型是 monad。这些就是“单子定律”,我将把它留给那些冗长的解释来进行完整的解释。我将这些定律总结为“(>>= return) 是一个恒等函数,而 (>>=) 是关联函数。”即使可以更准确地表达,实际上也仅此而已。

这就是单子的全部内容。如果您可以在保留这些行为属性的同时实现该接口,那么您就拥有了一个 monad。

该解释可能比您预期的要短。那是因为 monad 接口确实非常抽象。令人难以置信的抽象级别是为什么这么多不同的事物可以建模为单子的部分原因。

不太明显的是,尽管接口很抽象,但它允许对任何控制流模式进行通用建模,而不管实际的 monad 实现如何。这就是为什么 GHC 的 base 库中的 Control.Monad 包具有 whenforever 等组合符。这就是为什么显式抽象任何 monad 实现的能力非常强大,尤其是在类型系统的支持下。

Ok, using Haskell terminology and examples...

A monad, in functional programming, is a composition pattern for data types with the kind * -> *.

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

(There's more to the class than that in Haskell, but those are the important parts.)

A data type is a monad if it can implement that interface while satisfying three conditions in the implementation. These are the "monad laws", and I'll leave it to those long-winded explanations for the full explanation. I summarize the laws as "(>>= return) is an identity function, and (>>=) is associative." It's really not more than that, even if it can be expressed more precisely.

And that's all a monad is. If you can implement that interface while preserving those behavioral properties, you have a monad.

That explanation is probably shorter than you expected. That's because the monad interface really is very abstract. The incredible level of abstraction is part of why so many different things can be modeled as monads.

What's less obvious is that as abstract as the interface is, it allows generically modeling any control-flow pattern, regardless of the actual monad implementation. This is why the Control.Monad package in GHC's base library has combinators like when, forever, etc. And this is why the ability to explicitly abstract over any monad implementation is powerful, especially with support from a type system.

笑梦风尘 2024-12-24 11:25:41

您应该阅读 Eugenio Moggi 的论文“计算和单子的概念”,该论文解释了当时提出的单子在构建有效语言的指称语义方面的作用。

还有一个相关的问题:

参考文献学习像 Haskell 这样的纯函数式语言背后的理论?

因为你不想挥手,所以你必须阅读科学论文,而不是论坛答案或教程。

You should read the paper by Eugenio Moggi "Notions of computations and monads" which explain the then proposed role of monads to structure denotational semantic of effectful languages.

Also there is a related question:

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

As you don't want hand-waving, you have to read scientific papers, not forum answers or tutorials.

野稚 2024-12-24 11:25:41

单子是endofunctors类别中的幺半群,有什么问题吗?

抛开幽默不谈,我个人认为,在 Haskell 和函数式编程中使用的 monad,从 monads-as-an-interface 的角度可以更好地理解(如在卡尔和丹的回答中)而不是从单子作为类别理论中的术语的角度来看。我必须承认,当我不得不使用 单子

您提到您不喜欢所有“大量示例”教程。有没有人向您指出尴尬的小队 纸?它重点关注 IO monad,但引言对 Haskell 最初采用 monad 概念的原因提供了很好的技术和历史解释。

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

Humor aside, I personally believe that monads, as they are used in Haskell and functional programming, are better understood from the monads-as-an-interface point of view (as in Carl's and Dan's answers) instead of from the monads-as-the-term-from-category-theory point of view. I have to confess that I only really internalized the whole monad thing when I had to use a monadic library from another language in a real project.

You mention that you didn't like all the "lots of examples" tutorials. Has anyone ever pointed you to the Awkward squad paper? It focuses manly in the IO monad but the introduction gives a good technical and historical explanation of why the monad concept was embraced by Haskell in the first place.

独夜无伴 2024-12-24 11:25:41

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

Monad 用于表示计算。您可以将一个普通的过程程序(基本上是一个语句列表)视为一堆组合计算。 Monad 是这个概念的概括,允许您定义语句的组成方式。每个计算都有一个值(可以是 ()); monad 只是确定通过一系列计算串起来的值的行为方式。

Do 表示法确实使这一点变得清晰:它基本上是一种特殊的基于语句的语言,可让您定义语句之间发生的情况。就好像你可以定义如何“;”使用类 C 语言工作。

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

希望这是一个清晰的解释,并非完全错误。

I don't really know what I'm talking about, but here's my take:

Monads are used to represent computations. You can think of a normal procedural program, which is basically a list of statements, as a bunch of composed computations. Monads are a generalization of this concept, allowing you to define how the statements get composed. Each computation has a value (it could just be ()); the monad just determines how the value strung through a series of computations behaves.

Do notation is really what makes this clear: it's basically a special sort of statement-based language that lets you define what happens between statements. It's as if you could define how ";" worked in C-like languages.

In this light all of the monads I've used so far makes sense: State doesn't affect the value but updates a second value which is passed along from computation to computation in the background; Maybe short-circuits the value if it ever encounters a Nothing; List lets you have a variable number of values passed through; IO lets you have impure values passed through in a safe way. The more specialized monads I've used like Gen and Parsec parsers are also similar.

Hopefully this is a clear explanation which isn't completely off-base.

望笑 2024-12-24 11:25:41

既然您在范畴论意义上理解单子,我将您的问题解释为关于函数式编程中单子的表示
因此,我的回答避免了对单子是什么的任何解释,或者对其含义或用途的任何直觉。

答案:在 Haskell 中,单子以某种类别的内部语言呈现为 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 是对象上的unit操作
  • >>=(Haskellers 发音为“bind”)是态射的扩展运算,但交换了前两个参数(参见扩展 (-)* 的常用签名:(a - >MB) -> ma -> m b

(这些映射本身内化C中的态射,这是可能的因为m :|C| ->C|)。

因此,Haskell 的 do 表示法(如果您遇到过这种情况)是 Kleisli 类别的内部语言。

Since you understand monads in the category-theoretic sense I am interpreting your question as being about the presentation of monads in functional programming.
Thus my answer avoids any explanation of what a monad is, or any intuition about its meaning or use.

Answer: In Haskell a monad is presented, in an internal language for some category, as the (internalised) maps of a Kleisli triple.

Explanation:
It is hard to be precise about the properties of the "Hask category", and these properties are largely irrelevant for understanding Haskell's presentation of monads.
Instead, for this discussion, it is more useful to understand Haskell as an internal language for some category C. Haskell functions define morphisms in C and Haskell types are objects in C, but the particular category in which these definitions are made is unimportant.

Parameteric data types, e.g. data F a = ..., are object mappings, e.g. F : |C| -> |C|.

The usual description of a monad in Haskell is in Kleisli triple (or Kleisli extension) form:

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

where:

  • m is the object mapping m :|C| -> |C|
  • return is the unit operation on objects
  • >>= (pronounced "bind" by Haskellers) is the extension operation on morphisms but with its first two parameters swapped (cf. usual signature of extension (-)* : (a -> m b) -> m a -> m b)

(These maps are themselves internalised as families of morphisms in C, which is possible since m :|C| -> |C|).

Haskell's do-notation (if you have come across this) is therefore an internal language for Kleisli categories.

污味仙女 2024-12-24 11:25:41

Haskell wikibook 页面 有很好的基本解释。

The Haskell wikibook page has a good basic explanation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文