Monad不是一个语法糖吗?

时间:2011-08-30 11:56:44

标签: haskell f# functional-programming

我经历过各种论文/文章/博客,而不是莫纳德。人们在各种背景下谈论它们,比如类别理论(世界上是什么?)等。经过所有这些并试图真正理解和编写monadic代码之后,我开始认识到monad只是语法糖(可能是最多的)所有人都得到了荣耀。无论是Haskell中的符号还是F#中的Computation Expressions,甚至LINQ都选择了许多运算符(记住LINQ语法也是C#/ VB中的语法糖)。

我的问题是,如果有人认为monad不仅仅是语法糖(通过嵌套方法调用),那么请用“实用性”而不是“理论概念”来启发我。

谢谢大家。

更新

在完成所有答案之后,我得出的结论是,在特定语言中monad概念的实现是通过语法糖驱动的,但monad概念本身与句法糖无关,是非常一般或抽象的概念。感谢每个机构的答案,使概念本身与其在语言中实现的方式之间有所区别。

6 个答案:

答案 0 :(得分:22)

Monad不是语法糖; Haskell有一些糖用于处理monad,但你可以在没有糖和操作员的情况下使用它们。因此,Haskell并不像其他语言那样真正“支持”monad,只是让它们更容易使用和实现。 monad不是编程结构,也不是语言特征;它是一种思考某些类型对象的抽象方式,当它被直接作为Haskell类型时,它提供了一种很好的方式来思考类型中的状态转移,这使得Haskell(或者实际上任何语言,当被认为是功能上的)做它的事情时。

答案 1 :(得分:14)

do表示法,计算表达式和类似的语言结构当然是语法糖。这很明显,因为这些结构通常根据它们的去除来定义。 monad只是一种支持某些操作的类型。在Haskell中Monad是一个类型类,它定义了那些操作。

所以回答你的问题:Monad不是一个语法糖,它是一个类型类,但是do表示法是语法糖(当然完全是可选的 - 你可以使用monads就好了do符号)。

答案 2 :(得分:12)

根据定义,Monads不是语法糖。它们是遵循少数法则的一系列值(列表,集合,选项类型,有状态函数,延续等)的操作(返回/单元,映射和连接)的三倍。在编程中使用时,这些操作表示为函数。在某些情况下,例如Haskell,通过使用类型类,可以在所有monad上多态地表达这些函数。在其他情况下,必须为每个monad为这些函数指定不同的名称或命名空间。在某些情况下,例如Haskell,有一层语法糖可以使这些函数的编程更加透明。

所以Monads不是关于嵌套函数调用本身,当然也不是关于他们的糖。它们是关于三个函数本身,它们运行的​​值的类型,以及这些函数遵守的规律。

答案 3 :(得分:5)

Monads是语法糖,与类和方法调用语法是语法糖相同。如果有点冗长,将面向对象的原则应用于诸如C之类的语言是有用且实用的。就像OO(以及许多其他语言特性)monad是一个想法,一种思考组织程序的方式。

Monadic代码可以让你编写代码的形状,同时将某些决定推迟到以后。 Log monad(可以是Writer的变体)可用于为支持日志记录的库编写代码,但让消费应用程序决定日志记录的位置(如果有的话)。你可以在没有语法糖的情况下做到这一点,或者你可以利用它,如果你正在使用的语言支持它。

当然还有其他方法可以获得这个功能,但这只是一个,希望是“实用”的例子。

答案 4 :(得分:1)

没有

你可以在模式方面更多地考虑Monad(或Haskell中的任何其他类型类)。 您会看到一个模式,并且每次都以相同的方式处理它,以便您可以对其进行概括。

在这种情况下,它是增值信息的模式(或者如果您喜欢某种行李中的数据 - 但这张照片不适用于每个monad)以及将这些信息链接在一起的方法。

句法上的含糖只是构成约束的一些不错的小方法;) 它是对事物的延伸;)

对于实际概念:只看异步工作流程或IO monad - 应该足够实用;)

答案 5 :(得分:1)

我首先称它为一种模式,即m a - > (a - > m b) - > m b(具有合理的行为)对于许多不同的问题/类型构造函数是方便的。

实际上非常方便,它应该在语言中提供一些语法糖。这是Haskell中的do符号,C#中的from,scala中的for符号。在实现({1}}在C#中,selectMany在scala中时,合成糖只需要遵守命名模式。如果Monad不是他们的库中的类型,那些语言就是这样做的(在scala中,可能会写一个)。请注意,C#也为模式Iterator执行此操作。虽然存在IEnumerable接口,但flatMap会根据方法的名称转换为对foreach / GetEnumerator / MoveNext的调用,而不管其类型如何。只有在完成翻译时,它才会检查所有内容是否已定义并且输入得好。

但是在Haskell中(也可能在Scala或OCaml中完成,非在C#中,我认为这在F#中也是不可能的),Monad不仅仅是基于命名模式的设计模式+合成糖。它是一个真正的API,软件组件,无论如何。

考虑(静态类型)命令式语言中的迭代器模式。您可以在适合的类中实施Current / MoveNext(或Current / hasNext)。如果有一些像C#这样的语法糖,那就已经非常有用了。但如果你把它作为一个界面,你可以立即做更多。您可以拥有适用于任何迭代器的计算。您可以在迭代器(查找,过滤器,链,嵌套......)上使用实用程序方法,使它们更强大。

当Monad是一种类型而不仅仅是一种模式时,你也可以这样做。您可以使用实用程序函数来使Monad更强大(在Control.Monad中),您可以计算要使用的monad类型是一个参数(请参阅Wadler的旧article,了解解释器如何可以通过monad类型和各种实例进行参数化。要拥有monad类型(类型类),您需要某种更高阶的类型,即需要能够使用类型构造函数进行参数化,而不是简单的数据类型。