iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 9
2
自我挑戰組

Julia語言—從入門到專案系列 第 9

[Day 09] Metaprogramming

Julia中,Lisp留下的最好的禮物就是metaprogramming。Julia體現了Lisp "code as a data structure"的精神

Program representation and evaluation

每個Julia程式都是生於字串

prog = "1 + 1"  # "1 + 1"

接著,字串會被解析,成為叫作Expr的物件

ex1 = parse(prog)  # :(1 + 1)
typeof(ex1)  # Expr

Expression

Expr包含了3個部份:

  • head:以一個Symbol來表示這個Expr的種類,而Symbol你可以把他當成電腦讀的懂的字串
  • args:代表著expression的參數,你可以想成是這些元素組成這個expression的
  • typ:表示這個Expr他回傳值的型別
ex1.head  # :call
ex1.args  # [:+, 1, 1]
ex1.typ  # Any

Expr也可以被直接建構,運算子會以prefix的方式建構,像以下這個樣子

ex2 = Expr(:call, :+, 1, 1)
ex1 == ex2  # true

在這邊的重點是,Julia的程式碼可以內在表示為資料結構,而資料結構可以被語言本身所接受。

dump(ex2)  # 這可以把Expr的資訊印出來
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol +
    2: Int64 1
    3: Int64 1
  typ: Any

Symbols

要宣告Symbol很簡單,只要加個:就好

:foo  # :foo
typeof(:foo)  # Symbol
:foo == Symbol("foo")  # true

Quoting

要宣告Expr也很簡單,只要用:()將他包住就可以了

ex = :(a + b * c + 1)  # :(a + b * c + 1)

大家可以看看他的結構,會發現ex.args的第3個是個ExprExpr還可以展開成其他東西
Julia的語法解析會這樣一層一層解析下去

dump(ex)
Expr
  head: Symbol call
  args: Array{Any}((4,))
    1: Symbol +
    2: Symbol a
    3: Expr
      head: Symbol call
      args: Array{Any}((3,))
        1: Symbol *
        2: Symbol b
        3: Symbol c
      typ: Any
    4: Int64 1
  typ: Any

另一種宣告Expr的方法

ex = quote
    x = 1
    y = 2
    x + y
end
quote
    x = 1
    y = 2
    x + y
end

Interpolation

Julia語言自己可以解析自己是個強大的功能,但是更強大的在後面

a = 1;
ex = :($a + b)  # :(1 + b)

這邊可以讓作為變數的a直接將值帶入,如此一來就可以直接做推斷

ex = :(a in $:((1, 2, 3)) )  # :(a in (1,2,3))

Evaluation

接著,解析完之後就是執行了!!

eval(:(1 + 2))  # 3

eval()會直接執行Expr,他會直接取用global variable,更可能會更改到他們

ex = :(x = 1)
x  # LoadError: UndefVarError: x not defined

這段程式當中只有建構Exprx沒有被宣告

eval(ex)
x  # 1

執行之後,x就有值了

Macros

應用以上的原理,macro就是這麼一個東西,他像一個函式一樣可以接受參數,他會回傳編譯過的Expr並執行

macro sayhello()
    return :( println("Hello, world!") )
end

@sayhello
Hello, world!

@sayhello這個macro將println("Hello, world!")這段程式碼編譯後,呼叫@sayhello就會直接執行了

macro sayhello(name)
   return :( println("Hello, ", $name) )
end

@sayhello("Bob")
@sayhello "Bob"
Hello, Bob
Hello, Bob

參數有以上兩種給法,可以不用括弧

今天介紹了Julia的macro這個強大的工具,他其在在Lisp, C等等語言中也被應用的,Julia裏面有很多功能都被寫成macro的形式。


上一篇
[Day 08] 函數式程式設計
下一篇
[Day 10] Julia是個什麼樣的語言
系列文
Julia語言—從入門到專案31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言