【问题标题】:Isn't Monad just a syntactic sugar?Monad 不只是语法糖吗?
【发布时间】:2011-08-30 11:56:43
【问题描述】:

我浏览过各种论文/文章/博客,而 Monads 则不然。人们在诸如类别理论(这到底是什么?)等各种上下文中谈论它们。在经历了所有这些并尝试真正理解和编写单子代码之后,我了解到单子只是语法糖(可能是最赞美他们所有人)。无论是 Haskell 中的 do 表示法还是 F# 中的计算表达式,甚至是 LINQ 多选运算符(请记住 LINQ 语法也是 C#/VB 中的语法糖)。

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

谢谢大家。

更新:

在浏览完所有答案后,我得出的结论是,在特定语言中实现 monad 概念是通过句法糖驱动的,但 monad 概念本身与句法糖无关,是非常笼统或抽象的概念。感谢每个人的回答,以明确概念本身和它在语言中的实现方式之间的区别。

【问题讨论】:

标签: haskell f# functional-programming


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    所以回答你的问题:Monad 不是语法糖,它是一个类型类,但是 do 表示法是语法糖(当然完全是可选的 - 你可以在没有 do 表示法的情况下使用单子很好)。

    【讨论】:

      【解决方案3】:

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

      因此,Monad 本身与嵌套函数调用无关,当然也与它们无关。它们是关于三个函数本身、它们所操作的值的类型以及这些函数遵循的规律。

      【讨论】:

        【解决方案4】:

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

        Monadic 代码可以让您编写代码的形状,同时将某些决定推迟到以后。 Log monad 可能是 Writer 的变体,可用于为支持日志记录的库编写代码,但让消费应用程序决定日志记录的去向(如果在任何地方)。您可以在完全不使用语法糖的情况下执行此操作,或者如果您使用的语言支持它,您也可以利用它。

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

        【讨论】:

          【解决方案5】:

          不,

          您可以更多地从模式的角度来考虑 Monad(或 Haskell 中的任何其他类型类)。 您看到一个模式,并且每次都以相同的方式处理它,这样您就可以对其进行概括。

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

          句法糖只是组成绑定的一些不错的小方法;) 它是事物的扩展;)

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

          【讨论】:

          • Monad 是使用 Haskell 中的类型类和 F# 中的计算表达式实现的概念。我的问题与类型无关——类是泛化模式的一种方式。
          • 但是 Monad 只不过是某种类型(类型)的一般模式——没有类型类(或用于泛型的更好的高级类型系统等),你很难找到更多在 F# 中,但并非不可能(搜索 functors、applicative functors 和 F# 有一些文章)
          【解决方案6】:

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

          实际上非常方便,值得在语言中提供一些语法糖。这是 Haskell 中的 do 符号,C# 中的 from,scala 中的 for 理解。语法糖在实现时只需要遵守命名模式(C# 中的selectMany,scala 中的flatMap)。这些语言在没有 Monad 成为其库中的一种类型的情况下做到这一点(在 scala 中,可以编写一个)。请注意,C# 也对模式迭代器执行此操作。虽然有一个 IEnumerable 接口,但 foreach 会根据方法的名称转换为对 GetEnumerator/MoveNext/Current 的调用,而与类型无关。只有在翻译完成后,它才会检查所有内容是否已定义且输入正确。

          但是在 Haskell 中(也可以在 Scala 或 OCaml 中完成,而不是在 C# 中,我相信这在 F# 中也是不可能的),Monad 不仅仅是设计模式 + 基于命名模式的语法糖。它是一个实际的 API、软件组件等等。

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

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

          【讨论】:

            猜你喜欢
            • 2011-03-09
            • 2022-11-29
            • 1970-01-01
            • 2014-09-18
            • 2011-03-08
            • 2013-11-28
            • 2015-09-04
            • 2016-07-25
            • 2020-10-03
            相关资源
            最近更新 更多