iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 8
1

以上我們已經介紹了Julia語言精心設計的物件導向。

這篇我來帶大家穿梭Julia的函數式程式設計!

Functional的世界

其實functional programming這東西並不是甚麼新玩意兒。

在二十年前帶起物件導向程式設計的風潮,但是有另一批研究學者獨自發展出函數式程式設計這東西,他們主張程式可以完全由function建構起來,只要將不同function加以排列組合就可以了,一直以來都是小眾市場,甚至還研發出了一個純函數式的語言--Haskell。

在開發大型軟體系統的時候,工程師們運用物件導向的方法,總是發現有些地方很難用物件導向的方法實現,這些地方就會選用函數式的語言來銜接。

近年來,各語言不斷將函數式的元素納進來,像Java8的Lambda expression、Stream等等,讓原本小眾的函數式程式設計變成了大家口耳相傳的典範。這是為什麼呢?

因為要做concurrency、parallelism,函數式程式設計可以線性地擴充執行序或是行程,這樣可以善用多核心CPU,但是對於物件導向的方法來說,擴充到一定的量的時候會遇到瓶頸,這時大家就轉而向分散式運算前進了。

讓我們來看看函數式程式設計吧!

Lambda表達式

作為functional programming的基礎,就是要將function看成跟變數同等地位。
變數可以做為function的參數傳入,但是有些語言做不到。

Lambda Expression,又稱為匿名函式,可以用非常簡短的方式定義函式,也不用為函式命名。

x -> x^2 + 2x - 1
(x -> x^2 + 2x - 1)(5)  # 34

這邊宣告了一個多項式的函式,他有一個input x,接著我們可以把5放進去,它就會幫我們算出結果。

f = x -> x^2 + 2x - 1
f(5)

我們也可以把函式指定給f這個變數,我們只要f(5)就可以呼叫它了。

First-class citizen

在Julia裏面,Functions是第一類物件(first-class objects)

什麼是第一類物件呢

也就是可以被作為參數傳遞給函式的東西,有支援第一類物件的語言才有辦法支援functional programming喔~~

接下來我們就來看它的作用吧

神奇的Map

如果你現在手上有一堆數字,你想把他們做平方,這時候大多數人都會用個for迴圈。
但是函數式的做法不太一樣。

a = x -> x^2
map(a, [1, 2, 3, 4])  # [1, 4, 9, 16]

先創造一個可以把數字平方的Lambda Expression,接著將他作為參數傳給mapmap會將第二個參數裡的元素都執行過這個Lambda Expression,再將它收集起來變成結果。

map(a, Set([1, 2, 3, 4]))  # Set([4,9,16,1])

集合也可以這樣用。

map(x -> Pair(string(x[1]), x[2]), Dict([1=>1, 2=>2, 3=>3]))

或是我們直接將Lambda Expression寫在map當中,並且應用在Dict上。

好用的Filter

我們來介紹函數式的if,他會將你給他的參數當成檢查條件,當條件成立的時候就選出那些元素回傳。

filter(x -> x < 5, [1, 3, 5, 7])  # [1, 3]

選出小於五的數字

u = map(x -> x^2, [1, 2, 3, 4, 5])
v = filter(x -> x < 10, u)
v

我們用mapfilter來個組合技,這樣就可以先把數字平方後選出小於十的了。
是不是很優雅呢?

巧妙的Reduce

這是個有點複雜的高階函式,但是懂的話很好用
當你考慮以下算式的時候:

x = 1 + 2 + 3 + 4 + 5

你通常會這麼算

x = (((1 + 2) + 3) + 4) + 5

reduce他會幫你把前兩個先執行一次運算,接著將這個結果跟下一個元素一起運算,直到沒有元素為止。

reduce(+, [1, 2, 3, 4, 5])  # 15

Reduce的應用

reduce可以幫我們做很多事情,像是蒐集迴圈的計算結果。
我們常常做的事情就是會用一個空的Array去蒐集迴圈當中的值,reduce可以幫我們去執行這件事。

f = x -> x^2 - 2
a = map(f, [1, 2, 3, 4, 5])  # 迴圈中的運算
b = reduce(push!, [], a)  # 蒐集結果
b

或是做更難的,做partition
也就是我想把連續相同的數字分在一起,所以他就會被分成一堆一堆的。

g = (x, y) -> (isempty(x))? ((y, ), ): (x[end][1] == y)? (x[1:end-1]..., (x[end]..., y)) : (x..., (y, ))
c = reduce(g, (), [1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4])

然後就會得到以下結果囉

((1,1,1),(2,2,2,2),(3,3,3,3,3,3),(4,))

上一篇
[Day 07] Julia的物件導向世界
下一篇
[Day 09] Metaprogramming
系列文
Julia語言—從入門到專案31

尚未有邦友留言

立即登入留言