Python 使用Lisp宏可以做什么';与一流函数无关?
我想我了解Lisp宏及其在编译阶段的作用 但是在Python中,可以将一个函数传递到另一个函数中Python 使用Lisp宏可以做什么';与一流函数无关?,python,macros,lisp,Python,Macros,Lisp,我想我了解Lisp宏及其在编译阶段的作用 但是在Python中,可以将一个函数传递到另一个函数中 def f(filename, g): try: fh = open(filename, "rb") g(fh) finally: close(fh) 所以,我们在这里得到了惰性评估。如何处理宏而不是将函数作为第一类对象?宏在编译时展开。闭包是在运行时构造的。使用宏可以实现嵌入式领域特定语言的
def f(filename, g):
try:
fh = open(filename, "rb")
g(fh)
finally:
close(fh)
所以,我们在这里得到了惰性评估。如何处理宏而不是将函数作为第一类对象?宏在编译时展开。闭包是在运行时构造的。使用宏可以实现嵌入式领域特定语言的高效编译器,而使用高阶函数只能实现低效的解释器。eDSL编译器可能会执行各种静态检查,执行您希望实现的任何昂贵的优化,但当您只有运行时时,就无法执行任何昂贵的优化 不用说,宏为您的EDSL和语言扩展提供了更灵活的语法(字面意思是任何语法)
有关更多详细信息,请参阅此问题的答案:以下是Matthias Felleisen 2002年的答案(via): 我想建议有 宏的三种严格用法:
(web查询([姓氏]) (字符串加上“你好”的名字“你最后的名字是什么 姓名?】) …姓…名…)与 程序和网络消费者暗示。
[注:在ML中,您可以编写 web查询(fn last name=>…)字符串_append(…)但是由golly 这是一种痛苦,也是一种不必要的痛苦 模式。]
[注意:在Haskell中,您不需要这样做 一个。]
更多阅读:Paul Graham关于Lisp(Graham绝对不同意Felleisen的观点,即这些是宏的唯一有用的用途)和Shriram Krishnamurthi的论文《通过宏的自动机》(Automata via macros)()。首先Lisp也有一流的函数,所以你可以问:“如果我已经有一流的函数,为什么我需要Lisp中的宏?”答案是一流的函数不允许你使用语法 从表面上看,一流函数允许您编写
f(文件名,某些函数)
或f(文件名,lambda fh:fh.whatever(x))
,但不允许编写f(文件名,fh,fh.whatever(x))
。尽管可以说这是件好事,因为在最后一种情况下,fh
突然从何而来还不太清楚
更重要的是,函数只能包含有效的代码。因此,您不能编写一个高阶函数reverse\u function
,它将函数作为参数并“反向”执行,这样reverse\u function(lambda:“hello world”print)
将执行print“hello world”
。使用宏就可以做到这一点。当然,这个特定的示例非常愚蠢,但在嵌入特定于域的语言时,这个功能非常有用
is_number(if true do 1+2 end)
is_number(if true, do: (1+2))
例如,您无法在python中实现common lisp的
循环
构造。见鬼,如果python中的构造不是真正内置的,您甚至无法在python中实现python的For…in
构造,至少不能使用该语法。确保您可以为(集合、函数)实现类似的东西
,但那就不那么漂亮了。宏进行代码转换
宏转换源代码。惰性计算不会。假设您现在可以编写函数,将任意代码转换为任意不同的代码
非常简单的代码转换
简单的语言构造的创建也是一个非常简单的例子。考虑打开文件的例子:
(打开文件(流文件:方向:输入)
(做某事)
vs
(使用流调用(函数do something)
文件
:方向:输入)
宏给了我一个稍微不同的语法和代码结构
嵌入式语言:高级迭代构造
下面考虑一个稍微不同的例子:
(从10到20收集的i循环(sqr i))
vs
(收集10-20(功能sqr))
我们可以定义一个函数COLLECT-FOR
,它对一个简单的循环执行相同的操作,并具有用于开始、结束和步骤函数的变量
但是LOOP
提供了一种新的语言。LOOP
宏是这种语言的编译器。这种编译器可以执行LOOP
特定的优化,还可以在编译时检查这种新语言的语法。更强大的循环宏是ITERATE
。这些语言级别的强大工具现在可以n可以作为库编写,无需任何特殊的编译器支持
在宏中遍历代码树并进行更改
下面是另一个简单示例:
(带插槽(年龄名称)某人
(打印na)
is_number(if true do 1+2 end)
is_number(if true, do: (1+2))