- 论坛徽章:
- 2
|
回复 145# walleeee
元编程可以解决很多问题。
一种机制解决许多问题,而不是每个问题一个机制,导致语言根本就没法学完,比如C++。更好过那些根本就不想解决这些问题的语言。
比如现在就在首页的,吐槽不支持二进制literal。
程序员肯定知道如何将二进制的字符串表达,比如"111"转换成整数表达,7,只要一个int int_from_string(char const* s, int radix);
问题是这个函数是运行时而非编译时。
C++终于通过添加了user defined literal,可以让上面那个函数在编译时求值,获得一个编译时的值。
这是通过添加一种非常专用的机制。谁能预料到是否还有其他需求呢?有的话又在添加另外的机制?并且等到下一个标准支持,编译器实现?
在lisp里面根本就不需要等待语言去支持,lisp(至少el/cl)已经通过一种非常范化的机制提供了足够的支持。
而且在lisp里面,编写这种程序与编写其他的运行时使用的程序使用的是同一套机制。
比如emacs lisp里,运行时字符串到整数的转换是: (string-to-number "111" 2) ; => 7
让它在编译时被求值可以定义一个宏:
- (defmacro 0b (s) (string-to-number s 2))
- (setq x (0b "111"))
复制代码 编译上面的代码,就可以发现x是直接被设置为7而不需要运行时计算。
这是因为子程序(setq x (0b "111"))在编译时展开,得到另一个子程序,同时也是编译器最终编译的程序:(setq x 7)。
metadata是描述数据的数据,metaprogram就是产生程序的程序。
还可以让上面的程序在语法上更像C一点,比如:(setq x (c-style-literal 0b111) y (c-style-literal 0x7))。
cl还支持一种叫read-macro的东西,可以让代码更像一个literal, 比如: (setq x @b111 y @bx7)。
它可以在read-time将@b111转换为(c-style-literal 0b111)并让evaluator继续求值,甚至可以直接进行更多的计算返回7。
program-text -(read)-> lisp-object -(eval)-> result
可以在不同时期将程序转换为另一个程序让余下部分继续计算。
还是binary literal的例子,再从另一个角度说某种技术的易用性。
在C与C++03里,如果确实需要,是可以完成的。boost有个预处理库,可以BIANRY(111)。
C++可以 binary_literal<111>::value。
但因为它们的实现太繁琐(或者说猥琐)了,权衡一下,不如直接写0x7算了……
直到C++11,才让0b111真正可用。
现在可以说明你的疑问了:
>> 我觉得我写程序没有刻意去text->tree啊?
那是因为python里面要将程序transform到另一个程序太困难,所以这种技术不具有实用性。
自然就很难训练出code transformation这种思维,也就不会去想text->tree这回事。
|
|