【问题标题】:Metaprogramming - self explanatory code - tutorials, articles, books [closed]元编程 - 自我解释代码 - 教程、文章、书籍 [关闭]
【发布时间】:2011-02-03 16:00:25
【问题描述】:

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

谢谢!

【问题讨论】:

  • 元编程——比如 C++ 模板(与不言自明的代码相去甚远),还是别的什么?
  • @KennyTM:请参阅我编辑的问题。谢谢!
  • @stakx:“给定的示例(一种简单的绘图语言)以何种方式被视为元编程”。它是一个定义为元编程的解释器。
  • @JonHarrop:当时我可能误解了示例代码的目的。我正在查看实际的绘图代码并思考,“是什么让这成为一个元程序?”我还是会说不是。但我同意你的观点,为该绘图语言编写解释器/编译器将是一个元程序。 ——我特别难以理解我为什么要考虑预处理器。我删除了我上面的 cmets,它们很混乱。

标签: java metaprogramming coding-style


【解决方案1】:

从您的示例中,您似乎在谈论 domain specific languages(DSL),特别是内部 DSL。

Here 是关于 DSL 的大量书籍(关于 SQL 等 DSL)。

Martin Fowler 有一本书正在进行中,目前是online

Ayende 写了一本关于 DSLs in boo 的书。

更新:(跟随 cmets)

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

您的示例显示了一个可由元程序用来控制绘画程序的 DSL。

【讨论】:

  • DSL 和元编程有区别吗?我的意思是它们是两种不同的野兽还是一种来自另一种? (对我来说是新概念:))
  • @elena - 元编程是关于操纵其他程序或其数据的程序。有时元程序使用 DSL。
【解决方案2】:

嗯,在 Java 生态系统中,我认为实现迷你语言的最简单方法是使用脚本语言,例如 GroovyRuby(是的,我知道,Ruby 不是 Java 的本地公民生态系统)。两者都提供了相当好的 DSL 规范机制,这将允许您以比 Java 语言更简单的方式做到这一点:

不过,也有纯 Java 的替代方案,但我认为它们实现起来会有点困难。

【讨论】:

  • JRuby 是 Java 生态系统的本地公民。
  • 是的,当然,但是 Ruby 本身是作为一种独立语言创建的,具有自己的解释器/执行环境,提供比 JRuby 更多的原生资源集成。
【解决方案3】:

Tcl 最初是作为一种制造领域特定语言的方式,随着复杂性增长到需要获得通用编程能力的地步,这些语言并不糟糕。此外,添加您自己的命令仍然非常容易,因为这仍然是该语言的一个重要用例。

如果您想要一个与 Java 集成的实现,Jacl 是一个 Tcl in Java 的实现,它提供了专注于 DSL 的脚本能力,并且还可以访问任何Java 对象。

(元编程是编写程序来编写程序。有些语言比其他语言做得更多。为了了解一些特定情况,Lisp 是一种进行大量元编程的语言的经典示例;C++ 倾向于贬低它到模板,而不是在运行时允许它;脚本语言都倾向于发现元编程更容易,因为它们的实现被编写得更灵活,尽管这只是程度问题..)

【讨论】:

    【解决方案4】:

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


    举例说明:

    考虑以下递归函数,它生成Fibonacci series (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&lt;5&gt;::value.


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

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

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

    元编程是编写或操作其他程序(或它们自身)作为数据的计算机程序,或在编译时完成部分工作的计算机程序 否则会在运行时完成

    -- 来自Wikipedia article on metaprogramming 的定义,重点由我添加。

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

    【讨论】:

      【解决方案5】:

      欢迎来到元编程的美妙世界 :) 元编程实际上涉及到很多事情。我将尝试列出我想到的:

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

        还有很多关于 Lisp 的资源。

      • DSL。扩展一种语言语法和语义的能力现在被重新命名为“DSL”。创建 DSL 的最简单方法是使用 interpreter pattern。然后来internal DSLfluent interface 和外部DSL(按照Fowler 的术语)。这是我最近观看的一个不错的视频:

        其他答案已经指向该领域的资源。

      • 反思。元编程也离不开形式反射。在运行时反思程序结构的能力非常强大。那么了解introspectionintercessionreification 是什么很重要。恕我直言,反射允许两大类事情:1.在编译时对其结构未知的数据进行操作(然后在运行时提供数据结构并且程序仍然以反射方式工作)。 2. 强大的编程模式,如dynamic proxy、工厂等。Smalltalk 是探索反射的首选,everything 都是反射的。但我认为 Ruby 也是一个很好的候选者,因为它有一个利用元编程的社区(但我自己对 Ruby 了解不多)。

        关于反思的文献也很丰富。

      • 注释。注释可以被视为一种语言反射能力的一个子集,但我认为它应该有自己的类别。我已经回答过一次what annotations are and how they can be used。注释是可以在编译时或运行时处理的元数据。 Java 通过annotation processor toolPluggable Annotation Processing APImirror API 对其提供了良好的支持。

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

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

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

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

      【讨论】:

        【解决方案6】:

        你可以看看eclipse modeling project,他们支持元模型。

        【讨论】:

          【解决方案7】:

          Pluralsight 上有一个关于元编程的课程,这可能是一个很好的切入点https://app.pluralsight.com/library/courses/understanding-metaprogramming/table-of-contents

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-03-21
            • 2010-09-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多