这是我目前的尝试:
Monad 是 桶旅:
- 每个操作都是一个人排队;即,操作发生的顺序很明确。
- 每个人将一个桶作为输入,从中取出东西,然后将新的东西放入桶中。桶又会被传递给旅中的下一个人(通过绑定或
>>= 操作)。
-
return 操作只是将东西放入桶中的操作。
- 在顺序 (
>>) 操作的情况下,桶的内容在传递给下一个人之前被转储。下一个人不在乎桶里有什么,他们只是在等待接收。
- 对于
() 上的monad,一张票在桶内传递。它被称为“单元”,它只是一张白纸。
- 在 IO monad 的情况下,每个人都会大声说出一些非常深刻或非常愚蠢的话——但他们只能在拿着桶的时候说话。
希望这会有所帮助。 :-)
编辑:感谢您的支持,但遗憾的是,Monad 教程的诅咒又来了。我所描述的只是带有容器的函数应用程序,而不是单子!但我不是虚无主义者——我相信 Monad Tutorial 的诅咒可以被打破!所以这里有一张更,嗯,复杂的图片,我认为它更好地描述了它。您决定是否值得带给您的朋友。
Monad 是一个项目经理组成的团队。项目经理站在除了该旅的第一名成员之外的所有人后面。水桶大队的成员坐在凳子上,前面放着水桶。
第一个人收到一些东西,用它做某事,然后把它放在桶里。然后那个人放手——不给旅里的下一个人,那太容易了! :-) – 但对站在那个人背后的项目经理。
项目经理(她的名字是 bind 或 >>=)拿起存储桶并决定如何处理它。她可能决定把第一个人的东西从桶里拿出来,然后毫不犹豫地把它交给她面前的人(这就是 IO monad)。她可能会选择扔掉水桶并结束大队(即fail)。她可能决定绕过她面前的人,毫不费力地将水桶传给旅中的下一位经理(这就是 Maybe monad 中的 Nothing 发生的情况)。她甚至可能决定把桶里的东西拿出来,一次一块地递给她面前的人! (这就是 List monad。)在序列 (>>) 的情况下,她只是轻拍她面前的人的肩膀,而不是递给他们任何东西。
当下一个人制作了一桶东西时,该人会将其交给下一位项目经理。下一位项目经理再次弄清楚如何处理她给的桶,并将桶中的东西交给她的人。最后,存储桶被返回传递给项目经理链,项目经理可以选择使用存储桶做一些事情(例如 List monad 组装所有结果)。结果,第一个项目经理产生了一桶东西。
在do 语法的情况下,每个人实际上都是在之前的所有内容的上下文中现场定义的操作 - 好像项目经理不仅传递存储桶中的内容,还传递该旅的前任成员产生的价值(呃,东西)。在这种情况下,如果您使用绑定和序列而不是使用do 语法来写出计算,则在这种情况下构建上下文会更容易查看——注意每个连续的“语句”都是在该点之前的操作中构造的匿名函数。
() 值、IO monad 和 return 操作仍然如上所述。
“但这太复杂了!为什么人们不能自己卸桶?”我听到你问。好吧,项目经理可以在幕后做大量工作,否则会使该人的工作复杂化。我们正在努力让这些旅团成员变得轻松,所以他们不必做太多事情。例如,在 Maybe monad 的情况下,每个人都不必检查他们被给予的东西的价值,看看他们是否被给予了任何东西——项目经理会为他们处理这些。
“好吧,那么,如果你真的想让每个人的工作更轻松,为什么不一路走下去——让一个人拿东西和交东西,让项目经理担心分桶?”经常这样做,并且它有一个特殊的名称,称为将人(呃,操作)提升到 monad。但是,有时,您需要一个人做一些更复杂的事情,他们希望对生成的存储桶进行一些控制(例如,在Maybe monad 的情况下,他们是否需要返回Nothing),并且这就是 monad 所提供的。
要点是:
- 操作按顺序排列。
- 每个人都知道如何制作水桶,但不知道如何从水桶中取出东西。
- 每个项目经理都知道如何处理存储桶,以及如何从中取出东西,但并不关心其中的内容。
我的睡前教程到此结束。 :-P