简介编程
元编程是Lisp最强大的特性(参考官方文档介绍,我没有用过Lisp),元编程即将代码视做程序自己的数据结构,它使得程序能够改变生成本身的代码。
一、程序表示数据结构
这里介绍两种建立表达式的方式Meta.parse和Expr。code
1). 用字符串表示代码,而后用Meta.parse转换成表达式,如:对象
julia> prog = "1 + 1" "1 + 1" julia> ex1=Meta.parse(prog) :(1 + 1)
2). 也能够直接经过表达式对象生成:element
julia> ex2 = Expr(:call, :+, 1, 1) :(1 + 1)
3) 表达式有两个部分,head和args:文档
julia> ex1.head :call julia> ex1.args 3-element Array{Any,1}: :+ 1 1
4) 或者直接用dump查看表达式:字符串
julia> dump(ex1) Expr head: Symbol call args: Array{Any}((3,)) 1: Symbol + 2: Int64 1 3: Int64 1
2.表达式与求值io
1). 冒号也能够用来建立表达式,和Meta.parse,Expr建立的表达式是等价的变量
julia> ex = :(a+b*c+1) :(a + b * c + 1)
2). 使用quote ... end结构建立表达式引用
julia> ex = quote x = 1 y = 2 x + y end quote #= none:2 =# x = 1 #= none:3 =# y = 2 #= none:4 =# x + y end
三、插值(Interpolation)
插值即插入表达式中的值,用$开头表示,以下表达式$a即插值,
julia> a = 1; julia> ex = :($a + b) :(1 + b) julia> ex1 = :(a+b) :(a + b)
它与直接使用变量的ex1区别在于,ex中a的值已经被写入表达式中a若是在后面改变了,ex不变;而ex1中a的值是随a变化,如:
julia> b=4 4 julia> eval(ex) 5 julia> eval(ex1) 5 julia> a=3 3 julia> eval(ex) 5 julia> eval(ex1) 7
四、嵌套引用表达式
使用quote...end 能够定义多行表达式,也能够定义单行表达式。甚至能够多层嵌套:
julia> x = :(1 + 2); julia> e = quote quote $x end end quote #= none:1 =# $(Expr(:quote, quote #= none:1 =# $(Expr(:$, :x)) end)) end
e是嵌套表达式。注意这里有一个Expr(:$, :x),代表x并无被求值,它属于内层表达式。
对e求值能够获得内层表达式,这时$x会被求值:
julia> eval(e) quote #= REPL[2]:1 =# 3 + 4 end
使用双$符能够将x的值插入:
julia> e = quote quote $$x end end quote #= none:1 =# $(Expr(:quote, quote #= none:1 =# $(Expr(:$, :(1 + 2))) end)) end
这里x已经被求值了,这个表达式定义以后就不随x改变了。
对e求值产生插值3:
julia> eval(e) quote #= none:1 =# 3 end
看一下多层嵌套的例子:
julia> e2=quote quote quote $$x end end end quote #= REPL[37]:1 =# $(Expr(:quote, quote #= REPL[37]:1 =# $(Expr(:quote, quote #= REPL[37]:1 =# $(Expr(:$, :($(Expr(:$, :x))))) end)) end)) end julia> e3=quote quote quote $$$x end end end quote #= REPL[38]:1 =# $(Expr(:quote, quote #= REPL[38]:1 =# $(Expr(:quote, quote #= REPL[38]:1 =# $(Expr(:$, :($(Expr(:$, :(4 + 6)))))) end)) end)) end