元编程 - 自解释代码 - 教程,文章,书籍

ele*_*ena 19 java coding-style metaprogramming

我正在研究改进我的编程技巧(实际上我每年都尽力减少吸收,就像我们的Jeff Atwood所说的那样),所以我正在考虑阅读有关元编程和自解释代码的内容.

我正在寻找类似白痴的指南(免费下载书籍,在线资源).此外,我想要的不仅仅是普通的wiki页面,还有一些语言不可知或最好是Java示例.

你是否知道有这样的资源可以有效地将所有这些资源付诸实践(我知道所有这些经验都有很多话要说但我有点想要建立避免流程错误决策 - 经验 - 良好决策的经验)?

编辑:

来自Pragmatic Programmer的这个例子的一些东西:

...实现一种迷你语言来控制一个简单的绘图包......该语言由单个字母命令组成.一些命令后跟一个数字.例如,以下输入将绘制一个矩形:

P 2 # select pen 2
D # pen down
W 2 # draw west 2cm
N 1 # then north 1
E 2 # then east 2
S 1 # then back south
U # pen up
Run Code Online (Sandbox Code Playgroud)

谢谢!

ewe*_*nli 33

欢迎来到元编程的精彩世界:)元编程实际上涉及很多事情.我会尝试列出我的想法:

  • .首先在术语下探讨了扩展编程语言的语法和语义的能力.有几种语言的结构类似于宏,但选择的选择当然是Lisp.如果您对元编程感兴趣,那么理解Lisp和宏系统(以及代码和数据具有相同表示的语言的同音性)绝对是必须的.如果你想要一个在JVM上运行的Lisp方言,那就去Clojure吧.一些资源:

    还有很多关于Lisp的资源.

  • DSL.扩展一种语言语法和语义的能力现在在术语"DSL"下重新命名.创建DSL的最简单方法是使用解释器模式.然后是具有流畅接口和外部DSL的内部DSL(根据Fowler的术语).这是我最近观看的一段精彩视频:

    其他答案已经指出了该领域的资源.

  • 反思.元编程也是不可分割的形式反映.在运行时反映程序结构的能力非常强大.那么了解什么是内省,代祷具体化是很重要的.恕我直言,反射允许两大类事物:1.数据的操作,其结构在编译时是未知的(然后在运行时提供数据的结构,并且程序仍然可以反射).2.强大的编程模式,如动态代理,工厂等.Smalltalk是探索反射的首选,一切都是反射性的.但我认为Ruby也是一个很好的候选者,有一个利用元编程的社区(但我自己对Ruby不太了解).

    还有关于反思的丰富文献.

  • 注释.注释可以被视为语言反射能力的一个子集,但我认为它应该属于自己的类别.我已经回答了注释是什么以及如何使用它们.注释是可以在编译时或运行时处理的元数据.Java通过注释处理器工具,Pluggable Annotation Processing API镜像API提供了很好的支持.

  • 字节码或AST转换.这可以在编译时或运行时完成.这在某种程度上是低级方法,但也可以被认为是元编程的一种形式(在某种意义上,它与非同性语言的宏相同.)

结论:元编程是程序自我推理或修改自身的能力.就像元堆栈溢出一样,可以询问有关堆栈溢出本身的问题.元编程不是一种特定的技术,而是概念和技术的集合.

有几件事情属于元编程的范畴.从您的问题来看,您似乎对宏/ DSL部分更感兴趣.但一切都是最终相关的,因此元编程的其他方面也是值得关注的.

PS:我知道我提供的大部分链接都不是教程或介绍性文章.这些是我喜欢的资源,它描述了元编程的概念和优点,我认为这更有趣

  • +1,很好的答案:-) (2认同)

sta*_*ica 7

我在上面的评论中提到了 C++ 模板元编程。因此,让我提供一个使用 C++ 模板元编程的简短示例。我知道您用 标记了您的问题java,但这可能很有洞察力。我希望你能够理解 C++ 代码。


举例演示:

考虑以下递归函数,它生成斐波那契数列(0, 1, 1, 2, 3, 5, 8, 13, ...):

unsigned int fib(unsigned int n)
{
    return n >= 2 ? fib(n-2) + fib(n-1) : n;
}
Run Code Online (Sandbox Code Playgroud)

要从斐波那契数列中获取一项,您可以调用此函数(例如fib(5)),它将计算该值并将其返回给您。到目前为止没有什么特别的。


但现在,在 C++ 中,您可以使用模板(有点类似于 Java 中的泛型)重写此代码,这样斐波那契数列就不会在运行时生成,而是在编译时生成

// fib(n) := fib(n-2) + fib(n-1)
template <unsigned int n>
struct fib                     // <-- this is the generic version fib<n>
{
    static const unsigned int value = fib<n-2>::value + fib<n-1>::value;
};

// fib(0) := 0
template <>
struct fib<0>                  // <-- this overrides the generic fib<n> for n = 0
{
    static const unsigned int value = 0;
};

// fib(1) := 1
template <>
struct fib<1>                  // <-- this overrides the generic fib<n> for n = 1
{
    static const unsigned int value = 1;
};
Run Code Online (Sandbox Code Playgroud)

要使用此模板从斐波那契数列中获取项目,只需检索常量值 - 例如fib<5>::value


结论(“这与元编程有什么关系?”):

在模板示例中,是 C++ 编译器在编译时生成斐波那契数列,而不是您的程序在运行时生成。(这一点从以下事实中可以明显看出:在第一个示例中,您调用一个函数,而在模板示例中,您检索一个常量值。)您无需编写计算斐波那契数的函数即可获得斐波那契数!您不是对这个函数进行编程,而是对编译器进行了编程,让它为您做一些它没有明确设计的事情……这是非常了不起的。

因此,这是元编程的一种形式:

元编程是编写或操作其他程序(或程序本身)作为其数据的计算机程序,或者在编译时完成本应在运行时完成的部分工作

--维基百科关于元编程的文章中的定义,重点是我添加的。

(另请注意上述模板示例中的副作用:当您让编译器预先计算斐波那契数时,它们需要存储在某处。程序二进制文件的大小将按比例增加到n包含术语fib<n>::value。从好的方面来说,您可以节省运行时的计算时间。)


Ode*_*ded 3

从您的示例来看,您似乎正在谈论领域特定语言(DSL),特别是内部 DSL。

这里有大量关于 DSL 的一般书籍(关于像 SQL 这样的 DSL)。

Martin Fowler 有一本书正在编写中,目前已上线

Ayende在 boo 中写了一本关于 DSL 的书。

更新:(以下评论)

元编程是关于创建控制其他程序(或其数据)的程序,有时使用 DSL。在这方面,批处理文件和 shell 脚本可以被视为元编程,因为它们调用和控制其他程序。

您的示例显示了元程序可以使用的 DSL 来控制绘画程序。