2014-11-03 160 views
4

在这里,我的一般焦点是Scala和Lisp/Scheme宏,不完全是在C/C++/Obj-C中的那些我只是看不到这一点。宏的目的是什么?

我理解它的方式是,宏有扩展语言。但功能也是如此。

我知道有些东西由于某些语言的限制而不能干净地实现,因此需要一个宏来实现。但是我用宏看到的很多例子似乎都是使用普通函数很容易实现的东西。

那究竟是什么目的呢?清理宏或以其他方式,有人请赐教。如果可能的话,请提供一些可以在宏中完成的示例代码,但对于普通函数来说是不可能的/难以做到的。

+0

http://stackoverflow.com/questions/267862/what-makes -lisp-macros-so-special?s = 6 | 1.8097 http://stackoverflow.com/questions/5833033/in-lisp-code-is-data-what-benefit-does-that-provide/5833388?s = 11 | 1.6415#5833388 – 2014-11-04 11:05:30

+0

http://stackoverflow.c的副本om/questions/2561221/examples-of-what-lisps-macros-can-be-used-for?s = 7 | 4.5505 – 2014-11-04 11:07:00

回答

7

对Scala宏所做的事情有一个简明的总结:http://scalamacros.org/paperstalks/2014-02-04-WhatAreMacrosGoodFor.pdf。综上所述,已知宏可用于:1)代码生成,2)高级静态检查,3)授权特定于领域的语言。 Scala中的宏是基于类型的,为类似Lisp的语言中的宏提供了一个额外的强大的功能。

上面链接的幻灯片中的一些示例确实可以在没有宏的情况下实现,但结果或者缺乏某种意义(例如性能)或对用户过于复杂(例如因为重量级错误消息)。例如,Akka的输入渠道可以用纯粹的含义来实现,但编译速度和可理解性会受到影响。或者,scala/async可以作为一个编译器插件来实现,但是它将不得不依赖于内部编译器API,并且将更难以分发。

当然,宏不是银弹。当用户不是最佳选择时,显然存在用例,这在http://scalamacros.org/paperstalks/2014-03-01-MacrosVsTypes.pdf中概述。然而好奇的是,在许多情况下,既不是纯宏观的,也不是宏观的解决方案,而是精心构建的混合动力车最终成为最好的。

+0

我已编辑问题 – 2014-11-04 10:08:57

+0

第一个演示文稿中有几个示例。我不认为1,2,5,7和8在没有宏的情况下是可以实现的。 3和4可以通过高级的类型编程来完成,但是编译时和运行时的结果会比较慢,而且更难维护。 6可以近似,但用户体验会受到影响(错误消息,词汇不一致)。 – 2014-11-04 11:42:37

2

在Common Lisp和Scheme中,大部分特殊语法的确实现了其他特殊语法,即宏。

例如,Scheme和CL都有if,condcase,但只有if是原语句法。

标准定义的宏和你自己制定的宏没有什么特别之处。他们的行为和工作可以与原始人一样好。

宏含有使读者模糊和令人惊讶的代价。使用常见的命名约定,如with-*可能会有所帮助,但如果一个函数/过程可以完成这项工作,或者只能在少数几个地方使用该表单,则永远不应该使用宏。

+0

我编辑了问题 – 2014-11-04 10:09:48

1

有一些宏用于Lisp的(不知道斯卡拉)三个主要目的:

  • 定义:什么是创建并在适当的地方直接登记。示例:defun,defgeneric,defclass(来自标准),deftable(来自后现代)。
  • Unwind-protect包装:临时修改状态并确保在完成任务后修改状态。重复编写可能会很麻烦,所以我们创建一个简写。例如:with-open-file(标准),with-transaction(许多数据库库)。其他语言的生成:例如,CL-WHO(HTML),Parenscript(JavaScript)。通过在Lisp表单中生成其他语言的代码,我们可以使用其他语言的宏,即使它们本身不支持。

具体的例子:爪哇7引入的简写,以确保在try -blocks的Closable S上的闭合:

try (SomeClosable foo = openFoo()) { 
    foo.doSomething(); 
} 

其可以在Java 6仅被表示大致是这样的:

SomeClosable foo; 
try { 
    foo = openFoo(); 
    foo.doSomething(); 
} finally { 
    if (foo != null && foo.isOpen()) { 
     foo.close(); 
    } 
} 

Java开发人员不得不等待语言设计者实现此功能。 Lisp的开发者使用一个小宏:

(defmacro with-open-foo ((var &rest options) &body body) 
    `(let ((,var (open-foo ,@options))) 
    (unwind-protect 
     (progn ,@body) 
     (when ,var (close ,var))))) 

这样他就可以写

(with-open-foo (f :bar baz) 
    (do-some-foo f) 
    (and-something-else)) 

,而不是

(let ((f (open-foo :bar baz))) 
    (unwind-protect 
     (progn 
     (do-some-foo f) 
     (and-something-else)) 
    (when f (close f)))) 
+0

我编辑了问题 – 2014-11-04 10:10:24

+0

@ElectricCoffee:我编辑了答案。 – Svante 2014-11-04 10:38:31

+0

难道你不能只用'defun'作为函数来写-open-foo吗? – 2014-11-04 10:48:04