Python 使用Lisp宏可以做什么';与一流函数无关?

Python 使用Lisp宏可以做什么';与一流函数无关?,python,macros,lisp,Python,Macros,Lisp,我想我了解Lisp宏及其在编译阶段的作用 但是在Python中,可以将一个函数传递到另一个函数中 def f(filename, g): try: fh = open(filename, "rb") g(fh) finally: close(fh) 所以,我们在这里得到了惰性评估。如何处理宏而不是将函数作为第一类对象?宏在编译时展开。闭包是在运行时构造的。使用宏可以实现嵌入式领域特定语言的

我想我了解Lisp宏及其在编译阶段的作用

但是在Python中,可以将一个函数传递到另一个函数中

def f(filename, g):
  try:                                
     fh = open(filename, "rb") 
     g(fh)
  finally:
     close(fh) 

所以,我们在这里得到了惰性评估。如何处理宏而不是将函数作为第一类对象?

宏在编译时展开。闭包是在运行时构造的。使用宏可以实现嵌入式领域特定语言的高效编译器,而使用高阶函数只能实现低效的解释器。eDSL编译器可能会执行各种静态检查,执行您希望实现的任何昂贵的优化,但当您只有运行时时,就无法执行任何昂贵的优化

不用说,宏为您的EDSL和语言扩展提供了更灵活的语法(字面意思是任何语法)


有关更多详细信息,请参阅此问题的答案:

以下是Matthias Felleisen 2002年的答案(via):

我想建议有 宏的三种严格用法:

  • 数据子语言:我可以编写外观简单的表达式并创建 复杂的嵌套列表/数组/表 穿着整洁 宏

  • 绑定构造:我可以用宏引入新的绑定构造。 这帮我摆脱了lambda和 把东西放得更近 属于一起的。例如,一个 我们的教学包包含一个表单
    (web查询([姓氏]) (字符串加上“你好”的名字“你最后的名字是什么 姓名?】) …姓…名…)与 程序和网络消费者暗示。
    [注:在ML中,您可以编写 web查询(fn last name=>…)字符串_append(…)但是由golly 这是一种痛苦,也是一种不必要的痛苦 模式。]

  • 评估重新排序:我可以引入 推迟/推迟评估 根据需要使用表达式。想想循环, 新的条件、延迟/强制等
    [注意:在Haskell中,您不需要这样做 一个。]

  • 我知道Lisper使用宏 因为其他原因。老实说,我 我相信这部分是由于 编译器缺陷,部分原因是 对“语义”不规则的 目标语言

    我要求人们解决所有问题 当他们说X语言时有三个问题 可以做宏可以做的事情

    --马蒂亚斯

    费莱森是该领域最有影响力的宏观研究者之一(不过,我不知道他是否仍然同意这一观点)


    更多阅读: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))