元编程究竟是什么?

时间:2009-02-05 05:05:09

标签: metaprogramming

我正在ployglot programming on the Java platform上阅读有关TheServerSide的文章。文章中的一些评论将元编程称为生成代码的能力(可能即时)。

元编程能否动态生成代码,还是能够在运行时将方法和属性注入现有对象(就像Python,Ruby和Groovy等动态语言允许的那样)。

8 个答案:

答案 0 :(得分:73)

元编程是指程序了解自身或可以操纵自身的各种方式。

在像C#这样的语言中,反射是元编程的一种形式,因为程序可以检查有关自身的信息。例如,返回对象的所有属性的列表。

在ActionScript等语言中,您可以在运行时评估函数以创建新程序,例如eval(“x”+ i)。当S为1时,DoSomething()会影响名为x1的对象,当i为2时,会影响x2。 / p>

最后,元编程的另一种常见形式是程序可以以非平凡的方式改变自己。 LISP因此而闻名,这是Paul Graham十年前所倡导的。我将不得不查阅他的一些具体论文。但是这个想法是该程序将根据其状态改变程序的另一部分。这允许在运行时做出一定程度的灵活性,这在当今大多数流行语言中都是非常困难的。

值得注意的是,在直接汇编编程的好日子里,在运行时改变自身的程序是必要且非常普遍的。

保罗格雷厄姆的文章"What Made Lisp Different"

  

许多语言都有一种称为   宏。但是Lisp宏是独一无二的。和   信不信由你,他们做的是   与括号有关。该   Lisp的设计师没有把所有这些   语言中的括号只是为了   不同。致Blub程序员,   Lisp代码看起来很奇怪。但那些   括号是有原因的。   它们是a的外在证据   Lisp的根本区别   和其他语言。

     

Lisp代码由Lisp数据构成   对象。而不是琐碎的意义   源文件包含   字符和字符串是其中之一   语言支持的数据类型。   Lisp代码,经过它的读取   解析器,由数据结构组成   你可以穿越。

     

如果您了解编译器的工作原理,   真正发生的事情并非如此   那个Lisp有一个奇怪的语法   Lisp没有语法。你写程序   在生成的解析树中   在其他编译器内   语言被解析。但这些解析   您可以完全访问树木   程式。你可以编写程序   操纵它们。在Lisp中,这些   程序称为宏。他们是   编写程序的程序。

     

编写程序的程序?什么时候   你会想要那样做吗?不   很多时候,如果你在Cobol中思考。所有   如果你在Lisp中思考的话。它   如果可以的话,在这里会很方便   举一个强大的宏的例子,   并说那里!那个怎么样?但如果   我做了,它只是看起来像   对不认识的人胡言乱语   Lisp的;这里没有空间来解释   你需要知道的一切   明白它的意思。在Ansi Common Lisp我试图移动东西   我尽可能快,甚至如此   直到第160页我才开始使用宏。

     

但我想我可以给出一种   可能令人信服的论点。该   Viaweb编辑器的源代码是   可能大约20-25%的宏。宏   比普通的Lisp更难写   功能,它被认为是   当他们不是时,使用它们的坏风格   必要。所以该代码中的每个宏   是因为它必须是。什么   这意味着至少20-25%   这个程序中的代码正在执行   你不能轻易做的事情   其他语言。但是持怀疑态度   Blub程序员可能与我有关   声称神秘的力量   Lisp,这应该让他很好奇。   我们没有为我们编写此代码   自己的娱乐。我们是一个小小的创业公司   尽可能地编程   为了设置技术障碍   我们和竞争对手之间。

     

可疑的人可能会开始   想知道是否存在某种相关性   这里。我们的代码中有很大一部分是   做很难做的事情   用其他语言。所结果的   软件做了竞争对手的事情   软件无法做到。也许有   某种联系。我鼓励   你要遵循那个主题。也许有   更多的是那个老人蹒跚而行   在他的拐杖上,而不是眼睛。

答案 1 :(得分:33)

好问题。我很遗憾地看到目前没有一个答案能够正确回答你的问题。也许我可以帮忙......

元编程的定义非常简单:它意味着操纵程序的程序。

你接受的答案是说操纵自己的程序。这些确实是元程序,但它们是所有元程序的子集。

所有

  • 解析器
  • 特定于域的语言(DSL)
  • 嵌入式域特定语言(EDSL)
  • 编译器
  • 口译
  • 术语重写者
  • 定理证明

是元程序。因此GCC compiler是元节目,CPython interpreter是元节目,Mathematica computer algebra system是元节目,Coq theorem prover是元节目,依此类推。

其他答案断言元程序是生成其他程序的程序。这些确实是元程序,但同样,它们是所有元程序的子集。 Fastest Fourier Transform in the West(FFTW)库是这种元程序的一个例子。源代码主要在OCaml中编写,它生成一些C代码(称为codelet),这些代码被组合在一起以创建针对特定机器优化的高性能Fast Fourier Transform例程。该库实际上用于在Matlab中提供FFT例程。从FORTRAN的早期开始,几十年来人们一直在编写程序来生成数值方法。

第一种集成了元编程支持的编程语言是20世纪50年代后期的LISt处理器(LISP)语言。 LISP 1.5包含了许多使元编程更容易的功能。首先,LISP的核心数据类型是嵌套列表,即(a (b c) d)之类的树,这意味着任何LISP代码都可以原生地表示为数据结构。这被称为同质性。其次,可以使用QUOTE轻松地将LISP代码转换为数据。例如,(+ 1 2 3)添加1 + 2 + 3,(QUOTE (+ 1 2 3))创建一个在评估时添加1 + 2 + 3的表达式。第三,LISP提供了一个元循环求值器,允许您使用主机解释器或编译器在运行时评估LISP代码,包括运行时生成的LISP代码。 LISP的后代包括SchemeClojure。在所有这些语言中,元编程最常见于修改自身的程序形式,通常使用宏。

在20世纪70年代,Robin Milner开发了MetaLanguage(ML),演变成ML系列编程语言,包括Standard MLOCaml,并强烈影响HaskellF#。这些语言可以轻松表达其他语言。在这些语言中,元编程最常见的是词法分析器,解析器,解释器和编译器。

1994年,Erwin Unruh discovered that the C++ template system was Turing complete and could be used to execute arbitrary programs at compile time。 C ++模板元编程为未经洗涤的群众带来了元编程,他们(ab)将它用于许多不同的事情,包括在Blitz++ library中生成数值方法。

答案 2 :(得分:26)

好吧,元编程只是编程,但它基本上是“编写代码编写代码”

当程序可以观察和修改自己的结构和行为时,您提到的能力称为反射,它是一种元编程。

动态类型语言,具有强大的运行时反射功能,通过这些语言的解释性质实现...

静态类型语言也有强大的元编程技术,例如C ++ template metaprogramming ......

答案 3 :(得分:9)

这只是我个人的观点,这可能是元编程最自由的定义。

我认为它包括:

  1. 编译代码生成或运行时代码生成(或两者)
  2. 面向方面的思维或面向方面的编程
  3. DRY思考
  4. 我认为你可以通过使用其中任何一种并组合来实现目标:

    1. 反思
    2. DSL(域特定语言)
    3. 属性(.NET)或注释(Java)
    4. 泛型(.NET / Java)
    5. 模板(C ++)
    6. method_missing(Ruby)
    7. 闭包/头等职能/代表
    8. AOP - 面向方面编程

答案 4 :(得分:5)

元编程正在编写一个输出另一个程序的程序。这就像Lisp这样的语言非常擅长。使用支持真实宏的语言(不是C ++宏,而是可以操作它们输出的代码的语言)(如Ruby,Lisp,Scheme等)比使用Java这样的语言要容易得多。

一种实现是创建“域特定语言”,这是一种增强编程语言以完成特定任务的方法。如果正确完成,它可能会非常强大。 Ruby on Rails就是这种编程的一个很好的例子。

如果您有兴趣探索此方法,请查看Structure and Interpretation of Computer Programs,这是涵盖该主题的开创性书籍之一。

答案 5 :(得分:4)

  

元编程是指编写或操作其他程序(或自身)作为数据的计算机程序,或者在运行时执行部分工作的计算机程序,否则将在编译时完成。在许多情况下,这允许程序员在与手动编写所有代码所花费的时间相同的时间内完成更多工作,或者它为程序提供了更大的灵活性,无需重新编译即可有效地处理新情况。 (Source。)

基本上,它正在编写输出更多代码的代码,这些代码用于完成某些目标。这通常使用相同的语言(使用javascript创建javascript字符串,然后eval)或发出另一种语言(使用.NET创建Windows批处理文件)。

答案 6 :(得分:4)

wikipedia有一篇关于这个主题的好文章。人们不必对符合元编程的东西进行运行时修改。例如,许多人使用C ++模板在编译时进行元编程。

答案 7 :(得分:0)

让我们用简单的例子来理解这一点!

template<class T>
class Item{
private:
    std::string name;
    T value;
public:
    Item(std::string name, T value)
        : name{name}, value{value} {}
    std::string get_name() const {return name;}
    T get_value() const {return value;}
};

在这个例子中,T 可以是任何类型的值。例如,在这种情况下,我们期望整数或双精度数。 现在,这将编译,但不会生成任何代码。它只是一个蓝图。 当用户使用模板或蓝图的专用版本时,编译器将使用模板或蓝图生成代码。这就是元编程的意义所在!