1. 程式人生 > >Julia體驗 語言特性 超程式設計,巨集

Julia體驗 語言特性 超程式設計,巨集

上接語言基礎,個人感覺這門語言和自己心中的理想國相距較遠,乘著熱情還在,我挑一些有趣的東西再寫寫。

超程式設計

超程式設計即對程式碼進行處理的程式碼,可以使用Meta.parse()解析出引數程式碼的類AST表示,也可以使用quote ... end簡化:

julia> multiStmt = Meta.parse(raw"a=1;b=2;t=a;a=b;b=t;println(a,b)")
:($(Expr(:toplevel, :(a = 1), :(b = 2), :(t = a), :(a = b), :(b = t), :(println(a, b)))))

julia> typeof(multiStmt)
Expr

julia> ast = quote
x=1 y=2 res=x+y end quote #= REPL[21]:2 =# x = 1 #= REPL[21]:3 =# y = 2 #= REPL[21]:4 =# res = x + y end julia> typeof(ast) Expr

使用dump()獲得更可讀的表示:

julia> dump(multiStmt)
Expr
  head: Symbol toplevel
  args: Array{Any}((6,))
    1: Expr
      head: Symbol
= args: Array{Any}((2,)) 1: Symbol a 2: Int64 1 2: Expr head: Symbol = args: Array{Any}((2,)) 1: Symbol b 2: Int64 2 3: Expr head: Symbol = args: Array{Any}((2,)) 1: Symbol t 2: Symbol a 4: Expr head: Symbol
= args: Array{Any}((2,)) 1: Symbol a 2: Symbol b 5: Expr head: Symbol = args: Array{Any}((2,)) 1: Symbol b 2: Symbol t 6: Expr head: Symbol call args: Array{Any}((3,)) 1: Symbol println 2: Symbol a 3: Symbol b

expr有兩部分,expr.head表示出這個表示式的型別,expr.args表示出剩餘的引數:

julia> multiStmt.head
:toplevel

julia> multiStmt.args
6-element Array{Any,1}:
 :(a = 1)
 :(b = 2)
 :(t = a)
 :(a = b)
 :(b = t)
 :(println(a, b))

如果我們typeof head會發現,它是一種名為Symbol的型別:

julia> typeof(multiStmt.head)
Symbol

Symbol型別可以使用:name進行定義,也可以使用Symbol型別的構造建立:

julia> :str
:str

julia> typeof(:str)
Symbol

julia> Symbol("str2")
:str2

julia> typeof(Symbol("str2"))==typeof(:str)
true

最後我們使用eval()h函式傳入Expr型別引數求值:

julia> eval(ast)
3

julia> eval(multiStmt)
21

這就給了我們一種使用程式碼操縱程式碼的方式:

julia> add = Expr(:call,:-,:a,:b)
:(a - b)

julia> a = 1
1

julia> b= 2
2

julia> eval(add)
-1

巨集

Julia的巨集由macro ... end定義

julia> macro hello(name)
       return "hello,my name is "*name
       end
@hello (macro with 1 method)

julia> println(@hello("Andrew"))
hello,my name is Andrew

julia> println(@hello "Andrew")
hello,my name is Andrew

使用巨集可以像函式一樣加括號也可以巨集名 引數1 引數2 ...
類似C/C++的巨集的概念,Julia的巨集也是實施的替換操作
所以上述println(@hello "Andrew")會被替換為println("hello, my name is Andrew"),可以使用@macroexpand獲得展開後的結果

julia> @macroexpand println(@hello "Andrew")
:(println("hello,my name is Andrew"))