Julia元编程
元编程含义
julia元编程的含义,简单来说就是用代码写代码。代码的本质是字符串,把字串解析编译之后得到机器码,然后执行运算。这是高级程序语言想要运行的一个通用流程。那么Julia作为一种脚本语言,能够对字符串进行处理,把字符串解析为程序可以运行的表达式,调用函数运行改表达式,就实现了用代码写代码。
当然,“用代码写代码”只是元编程的一种体现,其功能非常强大,可以发挥巨大的作用。
元编程实现
要理解元编程,有三大要点:
- String类型(字符串)
- Symbol类型(符号)
- Expr类型(表达式)
通过一个实例来说明。
以下代码在Julia REPL中运行。
julia> str = "1+1"
"1+1"
首先,我们定义个字符串,str。现在这个字符串就只是一个字符串而已!如果,想要得到它的表达式结果2,怎么办呢?一种好的方法就是,把字符类型的1转化为整数类型的1,然后相加就可以了。但是,元编程不这么做,元编程直接把“1+1”转为表达式,也就是把字符串转化为可以执行的1+1。
也就是直接转为:
julia> 1 + 1
2
如何实现?
julia> Meta.parse(str)
:(1 + 1)
这样,就把它变成了表达式类型。(留意表达式类型的表达方式)
julia> typeof(Meta.parse(str))
Expr
然后可以直接对表达式运算。
julia> eval(Meta.parse(str))
2
Awesome!
那么我们来实现一个愚蠢想法,我要定义100个变量,然后求它们的和(简直不能再聪明了hhh)。
julia> for i in 1:100
str = "a" * string(i) * "=" * string(i)
eval(Meta.parse(str))
end
这个for循环中的str会生成 a1 到 a100,a1到a100分别等于1到100,*为字符串拼接。
神奇的事情发生了:
julia> a100 + a50
150
julia> a20 + a30 + a40
90
a1到a100都已经定义好了!
再来求个和!
julia> summ = 0
0
julia> for i in 1:100
str = "summ += a" * string(i)
eval(Meta.parse(str))
end
julia> summ
5050
有没有心灵的震撼!这不得点个赞?
那么,刚刚讲了Expr和String。Symbol呢?
Symbol会用在另一种构造的方式上。刚刚说的是用String解析成Expr,那么也可以直接构造Expr。一看就明白。
julia> ex = Expr(:call,:+,1,1)
:(1 + 1)
julia> eval(ex)
2
julia> a,b = 1,2
(1, 2)
julia> ex = Expr(:call,:+,:a,:b)
:(a + b)
julia> eval(ex)
3
用这种方法构造时,:a就是符号,在构造时:a绑定了符号a在内存中的值。
julia> ex = Expr(:call,:+,:a100,:a50)
:(a100 + a50)
julia> eval(ex)
150
julia> typeof(:a100)
Symbol
julia> typeof(:a50)
Symbol
使用dump可以查看表达式的信息,也就是查看抽象语法树的结构。
julia> dump(ex)
Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol +
2: Symbol a100
3: Symbol a50
其实也可以看到,在抽象语法树的描述中,都是Symbol,在通过String构造时,自动解析了而已。
小结
元编程能够构造表达式(抽象语法树),然后执行。方式有两种:
- 通过Srting解析得到。
- 通过Expr()直接构造。
最后,A给了B一个字符串,B通过parse,eval开启了新天地。B直接open一个文件,read一下,parse一下,eval一下,又是一片新天地…(很多语言都能够实现code generation,这一点毋庸置疑。Julia的优势在于,它比较简单方便。)