简介


元编程是Lisp最强大的特性(参考官方文档介绍,我没有用过Lisp),元编程即将代码视作程序本身的数据结构,它使得程序可以改变生成自己的代码。
1、程序表示


这里介绍两种创建表达式的方式Meta.parse和Expr。

1). 用字符串表示代码,然后用Meta.parse转换成表达式,如:

julia> prog = "1 + 1"
"1 + 1"

julia> ex1=Meta.parse(prog)
:(1 + 1)

2). 也可以直接通过表达式对象生成:

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.表达式与求值


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

3、插值(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

4、嵌套引用表达式


使用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


杜若
67 声望3 粉丝

引用和评论

0 条评论