元编程 - 不言自明的代码 - 教程,文章,书籍[已关闭]

2022-09-01 15:24:40

我正在考虑改进我的编程技巧(实际上,正如我们的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

谢谢!


答案 1

欢迎来到元编程的奇妙世界:)元编程实际上与许多事情有关。我将尝试列出我的想法:

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

    除此之外,关于Lisp还有很多资源。

  • 新浪网.扩展一种语言语法和语义的能力现在被重新命名为术语“DSL”。创建 DSL 的最简单方法是使用解释器模式。然后是具有流畅接口和外部DSL的内部DSL(根据Fowler的术语)。这是我最近看的一个很好的视频:

    其他答案已经指出了这一领域的资源。

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

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

  • 批注。注释可以被视为语言反思能力的子集,但我认为它应该有自己的类别。我已经回答过一次什么是注释以及如何使用它们。注释是可以在编译时或运行时处理的元数据。Java通过注释处理器工具可插拔注释处理API镜像API对它有很好的支持。

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

结论:元编程是程序对自己进行推理或修改自身的能力。就像元堆栈溢出是询问有关堆栈溢出本身的问题的地方。元编程不是一种特定的技术,而是概念和技术的集合。

有几件事属于元编程的保护伞。从你的问题来看,你似乎对宏/DSL部分更感兴趣。但一切都是最终相关的,所以元编程的其他方面也绝对值得一看。

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


答案 2

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


示例演示:

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

unsigned int fib(unsigned int n)
{
    return n >= 2 ? fib(n-2) + fib(n-1) : n;
}

要从斐波那契数列中获取项目,请调用此函数 - 例如 --,,它将计算该值并将其返回给您。到目前为止没什么特别的。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;
};

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


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

在模板示例中,在编译时生成斐波那契级数列的是C++编译器,而不是在程序运行时生成该序列。(从第一个示例中调用函数,而在模板示例中检索常量值的事实中可以明显看出这一点。你得到你的斐波那契数列,而不用写一个函数来计算它们!您没有对该函数进行编程,而是对编译器进行了编程,以为您执行一些并非明确设计用于...这是非常了不起的。

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

元编程是编写计算机程序,这些程序编写或操作其他程序(或它们自己)作为其数据,或者在编译时执行部分工作,否则将在运行时完成

--维基百科关于元编程的文章中的定义,强调由我添加。

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