元编程到底是什么?

我在 Java 平台上的 ployglot 编程上看到一篇关于服务器端的文章。本文中的一些注释将元编程称为生成代码的能力(可能是动态的)。

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

92310 次浏览

元编程是编写计算机程序,这些程序编写或操作其他程序(或自身)作为其数据,或者在运行时完成部分工作,否则这些工作将在编译时完成。在许多情况下,这允许程序员在手动编写所有代码的同样时间内完成更多的工作,或者给予程序更大的灵活性,以便在不重新编译的情况下有效地处理新的情况。(来源)

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

元编程是编写一个输出另一个程序的程序。这正是 Lisp 这样的语言所擅长的。在支持实际宏(不是 C + + 宏,而是能够操作它们输出的代码的宏)的语言(如 Ruby、 Lisp、 Scheme 等)中做这件事要比在 Java 这样的语言中做容易得多。

一种实现是创建一种“特定于领域的语言”,这是一种增强编程语言以完成特定任务的方法。如果处理得当,它会非常强大。RubyonRails 就是这类编程的一个很好的例子。

如果你对探索这种方法感兴趣,可以看看 计算机程序的构造和解释,它是涵盖这个主题的开创性书籍之一。

元编程指的是程序了解自己或能够操作自己的各种方式。

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

在 ActionScript 等语言中,可以在运行时计算函数,以创建 eval (“ x”+ i)等新程序。当 i 为1时 DoSomething ()将影响名为 x1的对象,当 i 为2时则影响 x2。

最后,元编程的另一种常见形式是当程序可以以非平凡的方式进行自我更改时。LISP 因此而闻名,这也是保罗•格雷厄姆(Paul Graham)大约10年前所倡导的。我得查查他的一些具体论文。但是这个想法是程序会根据它的状态改变程序的另一部分。这使得在运行时做出决策具有一定程度的灵活性,这在当今最流行的语言中是非常困难的。

同样值得注意的是,在以直接汇编方式编程的美好时代,在运行时改变自身的程序是必要的,而且非常普遍。

来自 Paul Graham 的文章 “是什么让 Lisp 与众不同”:

许多语言都有一种叫做 但是 Lisp 宏是独一无二的 信不信由你,他们做的是 与括号有关 Lisp 的设计者没有把所有这些 在语言中的括号只是为了 不同。对于 Blub 程序员来说, Lisp 代码看起来很奇怪,但是那些 括号的存在是有原因的。 他们是一个外在的证据 Lisp 之间的根本区别 以及其他语言。

Lisp 代码由 Lisp 数据构成 对象。而不是在琐碎的意义上 源文件包含的 字符,而字符串是 语言支持的数据类型。 控件读取 Lisp 代码之后 语法分析器,是由数据结构组成的 你可以穿越。

如果您了解编译器的工作原理, 真正发生的事情并不是这样的 Lisp 的语法很奇怪 Lisp 没有语法,你写程序 在生成的解析树中 在编译器中,当其他 语言是被解析的,但是这些解析 你完全可以接触到树木 程序。你可以编写程序 操纵它们。在 Lisp 中,这些 程序被称为宏,它们是 编写程序的程序。

写程序的程序? 什么时候 - 你想过这么做吗?-不想 很多时候,如果你用 Cobol 思考的话 时间,如果你用 Lisp 思考的话 如果可以的话,这里会很方便 给出一个强大宏的例子, 说出来! 怎么样? 但是如果 是的,看起来就像 对不知情的人胡言乱语 这里没有解释的余地 你需要知道的一切 我们理解这句话的意思 Common Lisp 我试着移动东西 我已经尽快了,即便如此 我直到第160页才开始读宏。

但我想我可以给一种 可能令人信服的论点 Viaweb 编辑器的源代码是 大概有20-25% 的宏,宏 比普通的 Lisp 更难写 函数,它被认为是 不用的时候用不好 所以代码中的每个宏 是因为它必须存在。什么 也就是说至少有20-25% 的 这个程序中的代码 在任何情况下都不能轻易做到的事情 无论多么怀疑 Blub 程序员可能是关于我的 宣称拥有神秘的力量 Lisp 这应该会引起他的好奇心。 我们写这个代码不是为了 我们只是个小小的创业公司, 尽我们所能编程 命令设置技术障碍 我们和我们的竞争对手之间。

一个可疑的人可能会开始 不知道是否有关联 这里,我们代码的一大部分是 做一些很难做的事情 在其他语言。结果 软件做了我们竞争对手的事情 软件做不到,也许有 某种联系,我鼓励 你跟随那个线索。有可能 对那个蹒跚而行的老人来说更重要 在他的拐杖上。

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

你提到的程序能够观察和修改自己的结构和行为的能力叫做反射,它是一种元编程。

动态类型语言具有强大的运行时反射特性,这是由于这些语言的解释特性..。

静态类型化语言也有强大的元编程技术,例如 C + + 模板超编程..。

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

我认为它包括:

  1. 编译代码生成或运行时代码生成(或两者兼而有之)
  2. 面向方面思维或面向方面编程
  3. 思考

我认为你可以通过使用以下任何一种方法并结合使用:

  1. 反射
  2. 领域特定语言
  3. 属性(.NET)或注释(Java)
  4. 泛型(. NET/Java)
  5. 模板(C + +)
  6. Method _ miss (Ruby)
  7. 闭包/第一类函数/委托
  8. 面向方面编程

问得好。我很遗憾目前没有一个答案能正确回答你的问题。也许我能帮上忙。

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

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

所有人:

  • 解析器
  • 领域特定语言(DSL)
  • 嵌入式领域特定语言(EDSLs)
  • 编译器
  • 翻译
  • 术语重写员
  • 定理证明

是元程序。所以 GCC 编译器是一个元程序,CPython 解释器是一个元程序,Mathematica 计算机代数系统是一个元程序,Coq 定理证明是一个元程序等等。

其他答案断言元程序是生成其他程序的程序。这些确实是元程序,但是,同样,它们是所有元程序的子集。西部最快的傅里叶变换(FFTW)库就是这种元程序的一个例子。源代码主要是用 奥卡姆编写的,它生成一些 C 代码(称为 codelets) ,这些代码组合在一起,创建了针对特定机器优化的高性能 快速傅里叶变换例程。这个库实际上是用来在 Matlab 提供 FFT 例程的。几十年来,人们一直在编写程序来生成数值方法,从 FORTRAN的早期开始。

第一个集成元编程支持的编程语言是20世纪50年代末的 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 的后代包括 计划Clojure。在所有这些语言中,元编程最常见的形式是修改自身的程序,通常使用宏。

在20世纪70年代,Robin Milner 开发了一种 元语言(ML) ,它演变成了包括 标准 ML奥卡姆在内的 ML 编程语言家族,并对 HaskellF # 产生了强烈的影响。这些语言使表达其他语言变得容易。在这些语言中,元程序最常见的形式是 lexer、解析器、解释器和编译器。

1994年,Erwin Unruh 发现 C + + 模板系统是完整的,可以用来在编译时执行任意程序。C + + 模板超编程把元编程带给了那些没有经验的大众,他们(ab)用它做了许多不同的事情,包括在 Blitz + + 库中生成数值方法。

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

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 可以是任何类型的值。 现在,这将编译,但它不会生成任何代码。它只是一个 蓝图。 当用户使用模板或蓝图的 专业的版本时,编译器将使用模板或蓝图生成代码。这就是元编程的意义所在!