在clojure中,我们应该何时使用monad而不是宏,反之亦然?

时间:2012-03-28 01:47:46

标签: macros clojure monads

monad上有太多的教程说......“看!这是我们可以使用monad的情况”或“这就是monad的用途”。我想知道的是,人们用什么步骤得出他们可以对自己说的结论 - “Gee Whiz!看起来我们可以在这里使用monad!”

所以,当有人告诉我......“(等等)与monad无关......”,它真的无法帮助我回答我的问题:

  • 如何确定使用monads表达程序中的哪种模式?
  • 当我发现使用它们的可能性时,如何编写我自己的自定义monad?

如果有人有兴趣帮助我,我在这里开始了一个关于monads的非常长的问题 - Map and Reduce Monad for Clojure... What about a Juxt Monad?

回到这个问题:

我们什么时候应该使用monad而不是宏?反之亦然?

  • 我读过文章和看过演示文稿说......'Monad用于DSL抽象'......但是大多数clojure DSL库(例如打嗝和korma)都在使用defmacro并且效果很好。

如果我们有宏,为什么我们需要在clojure中使用monad?

3 个答案:

答案 0 :(得分:36)

我现在已经使用Clojure两年了,而且我唯一一次使用monad作为练习来证明它可以完成。我从来没有将它们用于“真正的”代码。

Monads在Haskell中更常见,因为:

  • 它们是处理有状态计算的惯用方法。在Clojure中,您通常使用managed references处理状态,因此在Clojure中几乎不需要monad。
  • 同样适用于IO:Clojure允许您直接执行IO而不在您的类型中声明它,因此您不需要IO monad。

我的建议是专注于Clojure中的标准函数式编程。除非你看到你真的需要 monad,否则我不会投入太多时间试图引入它们。

宏是一个稍微不同的问题:它们用于编译时代码生成和语言语法的扩展(可能包括DSL,尽管DSL不一定需要宏)。当满足以下两个条件时,我使用宏:

  1. 我想以一种显着提高我解决特定问题域的能力的方式扩展语言语法。
  2. 无法获得与正常功能/功能组合相同的功能。如果可能,正常功能应该是您的首选:它们通常更易于编写和维护。
  3. P.S。如果你真的对Clojure的monads感兴趣,这里有两个我个人觉得非常好的视频:

答案 1 :(得分:16)

Monads和宏没有任何共同之处。它们用于解决不同的问题。在Clojure中,monad库非常广泛地使用宏来实现monad的语法“用户界面”。您可以使用monads在功能上实现某些库,而不是为外部接口添加一层宏。

至于“何时会在Clojure中使用monad”,我会看到两个用例:

1)为了完成这项工作,要在多个monad中实现有意义的东西    只有一次,然后“插入”monad。 Here就是一个很好的例子    虽然不幸(从教学的角度来看)是一种相当的方法    非平凡的应用:逻辑编程。

2)为了实现可以表述为monad的合成技术    从现有的monad基础设施中获利。

Clojure有两个内置monad,“let”(身份monad)和“for”(序列monad)。只要您希望以后可以将其中一个插入到代码中,就应该使用“domonad”。无论何时你希望你有类似但不完全相同的东西,你应该考虑编写自己的monad。

遗憾的是,这仍然相当抽象。目前在Clojure中使用monad的发布和抛光代码示例并不多。随着越来越多的Clojurians熟悉monad和更多Monad专家(通常来自Haskell)使用Clojure,这可能会改变。例如,我在Clojure中看过(但没有手头)monadic解析。

答案 2 :(得分:4)

@khinsen和@mikera很好地回答了这个问题,但很难再做出任何补充评论,我认为他们错过了一点(或者我在评论中找不到它)。

在Clojure中,宏是语言的一部分。是否使用它们,但它们在那里。事实上,你经常别无选择,只能使用它们,因为它们使你的应用程序更加惯用(这是专业使用任何语言的一个特征)。它们允许您预处理构成应用程序的数据结构。它们与其他语言结构类似,无论您的需求如何,它们都被包含在内。

与宏不同,monad不是Clojure的一部分。它们是使用语言的结构构建的,即宏。它们不会包含在运行时,除非您坚持要求它们存在。对我来说monad是用于组合计算的设计模式,因此它们类似于您可能熟悉的其他设计模式。您可以使用设计模式来开发模块化和有凝聚力的应用程序,无论是monad还是宏,还是您应该知道它们存在的任何其他语言构造,并为您的利益与它们合作。

关于你的问题,宏在monad进入之前工作。宏在编译阶段工作 - 他们将数据结构更改为其他数据结构。 Monads是一种组合计算的设计模式。这就是区别。在Clojure中,monad是使用宏编写的(为了使它们的使用更容易),因此人们倾向于说你可以用宏来轻松实现的monad。这是真的,因为它来自Clojure中的monads设计,但对于宏本身也可以这么说。你不需要在大多数时候写新的,the first rule of the macro club is to not write them,但他们仍然是语言的一部分,你应该非常了解他们的应用程序。

有关宏的更多讨论,请参阅How do Clojure programmers use Macros?