lisp宏在典型开发中是否真的有用?

时间:2015-10-03 13:42:53

标签: clojure scheme lisp elisp clojurescript

在Lisp中有很多关于宏的令人愉快的意见,但我真的找不到我可以在我的日常工作流程中使用的入门知识。我是网络开发人员,但使用emacs大约10年。我想了解宏是否对每个人都非常有用,或者它只是非常具体任务的杀手级功能。

大多数使用宏的引物都是在lisp上制作DSL的尝试。好吧它有时很有用,但据我所知,在商业开发中创建语法扩展是一种不好的做法。大多数语言都具有标准功能,例如,if,while,foreach运算符,类,名称空间,模块,闭包(lambdas)等常见概念。因此,所有程序通常都是从这些部分构建的,并且检查代码的新程序员已经知道这些部分并且可以操作它们。在基于宏构建DSL的情况下,程序员不仅需要探索业务逻辑,还需要学习DSL。商业开发对典型解决方案的重视,易于支持,程序员可以高度替换。

下一步 - 在宏上创建模板引擎。那么,行业标准现在是Twig,Jinja2,模板工具包 - 你可以创建自己的模板系统,但是......现在是2015年,而不是2001年Paul Graham的Viaweb创建时。现代模板系统彼此非常相似 - 它们开发了多年,它们有许多概念,如块,过滤器,继承,i18n。所以在2001年创造自己的模板引擎有意义,但现在有复杂的模板引擎适合所有生命的人。

接下来 - 使用宏创建独立于传递给它们的数据的算法。这个概念是有道理的,但它真的需要宏吗?例如,大多数脚本语言都支持通过引用传递函数 - 这意味着您可以创建抽象函数,它将接受数据和数据处理函数作为参数。当然,您需要创建一些数据处理函数来支持所有需要的数据类型,但是您将能够将所有这些函数传递给抽象函数,抽象函数将与可比较的lisp宏一样短。

下一步 - 算法本身。如今,我们90%的网络开发人员正在使用现成的库和算法。因此,即使我在前一段中完全错误,宏的作用在我们的工作中也很小。

所以你真的每天都使用宏,或者你只是非常优雅地使用宏来解决一些问题并在接下来的几个月内推断出这些问题吗?

2 个答案:

答案 0 :(得分:3)

宏在“典型开发”中肯定是有用的,因为如果做得好,它们可以在很多方面大大简化开发任务。例如,想想使用Compojure中精彩的defroutes宏在Clojure中编写的大量网站。或者在Clojure.core库本身,所有有用的宏,如whenif-let,或广泛使用的core.async库。它们都是宏,并且显着地使开发人员能够在没有它们的情况下做一些其他不那么容易的事情。

对于使用或不使用宏来构建自己的应用程序,通常应该避免它们,除非您别无选择,只能使用它们。当我转向宏时出现的两种最常见的场景:

  1. 我需要将参数传递给“函数”,但不要在调用站点对它们进行评估。宏是实现这一目标的唯一途径。
  2. Boilerplate和繁琐的重复代码设置是编写宏以简化操作的完美用例。
  3. 一般来说,功能很多更强大。您可以将函数存储为值。您可以将函数作为参数传递给另一个函数。您可以将功能组合成新功能。你不能用宏来做这些事情。

答案 1 :(得分:2)

报价

我在Clojure社区中多次看到引用:

  

数据>功能>宏

数据

为什么?好的数据是惊人的:您可以打印,转换,序列化以将其发送到网络......它也与语言无关。您可以将其转换为另一种表示形式,并让另一种语言编写的另一个程序使用它。这有多强大? 作为一个Clojurist,你可以看到几乎所有的Clojure函数都是为了操纵数据。它使操作数据变得很愉快。引用Fogus

  

良好的静态数据在编程中尽可能接近完美。然而,所有必须碰巧把它放在那里的垃圾......

<强>功能

接下来是函数:在lisp中我们很幸运能让它们镜像数据结构(列表),但它仍然比数据更不可组合。 例如,您可以merge代码吗?我们假设在这种情况下merge表示comp ose。你能说出函数的来源吗?你可以diff吗?所以从某种意义上说,功能是穷人的数据。

<强>的宏

但是Clojure试图减轻疼痛。它有一些工具可以做到这一点。有些是简单的(如meta,它实际上将数据附加到函数)或宏。 幸运的我们!我们有宏来操纵代码。它仍然不如操纵原始数据,但它让我们在那里。现在对于&#34;的通常论点,但函数是Clojure中的数据&#34; :有多少Clojure数据函数在函数上工作?但是有一个很大的不便之处。引用Eric Normand

  

宏在运行时是不透明的。

也就是说,他们不是一等公民,也不能将宏作为值传递。那么我们如何编写宏呢?更多宏?这感觉就像一条滑路。

到现在为止,您可以感觉到我们不想使用它们。它们当然非常强大(改变代码的代码?听起来很酷!)。

顺便说一句,我感觉(虽然我没有任何参考)Clojure试图以可读性为目标,而不是其他lisps的括号,以牺牲宏观写作为代价

简而言之,宏是一个强大的非常强大的工具,我不认为我会想用一种再也没有它的语言来编程。但你必须好好利用它。

<强>实施例

我能想到的宏的最经典用法是定义if构造。我们可以用功能吗?试试吧:

(defn if [condition if-true if-false]
   ...)

这可以吗?不,因为在将参数传递给函数时,它们将被评估。以下是:

(if true (println "true!") (println "false!)) ;; prints both "true!" and "false!"

宏不评估他们的论点,因此在这种情况下使用。你可以在[clojure.core][3]中找到一些。 至于典型的网页开发(定义&#34;典型的&#34;?),让我们看一下野外的一些宏。

[mori][3]中,wiki中有一个关于benchmarking的页面,我们可以在其中看到函数是使用多个arities定义的。导出这些函数的宏定义为here并使用there

在同一位作者中,我们可以查看[defui][6]的{​​{1}}宏。

我在野外看到的许多宏也只是为了简化声明,例如Om中的[defroute][6]

如果你有时间阅读我的答案,你一定要看"Zach Tellman - Always Be Composing"