演講:Functional Programming in Python



註:這場的 feedback 好像還蠻好的,爲了讓更多的人之後可以聽到這場演講,所以我決定移到 PyCon APAC 再講一次,大家可以到 PyCon APAC 2014 - Program 看一下議程:)

最近受邀到 Functinal Thursday 演講,本來是要我講 Erlang,不過因爲最近實在太忙沒有時間管 Erlang,所以我就改了主題講在 Python 上面實現一些 Functional Programming 的心得。

基本上也參考了國外講 Functioal Programming Python 的相關投影片,加上了一些自己做的實驗就上臺講了。

摘錄重點如下:

Functinoal Programming 在 Python 中是相容的

Python 大體上來說有提供很多的 functional feature:

  • Function as first-class citizen
  • Higher-order Function 高階函數(這點大概很容易被上一點滿足)
  • lambda 匿名函式
  • map/reduce/filter ❤(我的愛,我要很娘砲在這裏畫個愛心)
  • decorator

Decorator 是輕鬆模擬 functional feature 的關鍵

Curry 是個 functional programming 裏面的 pattern,大致上就是把一個 function 化成一串 function chain,chain 中的每個 function 都只 accept 一個 parameter。

以數學的表示法看是這樣的:((a × b × c) → d) → (((a → b) → c) → d)

所以以 Curry 爲例,如果我在 Python 中想要寫出一個 Curried function,我可以這樣做:

import functools

def curry(func):
    def curried(*args):
        if not args:
            return func()
        return curry(functools.partial(func, *args))
    return curried

def add(a, b, c, d, e):
    return a + b + c + d + e

curried_add = curry(add)

add12 = curried_add(1)(2)
add1234 = add12(3)(4)
add12345 = add1234(5)

print add12345()

這其實就是一個 decorator 的概念阿!一不小心我們就寫好一個 decorator 了:

@curry
def add(a, b, c, d, e):
    return a + b + c + d + e

add12 = add(1)(2)
add1234 = add12(3)(4)
add12345 = add1234(5)

print add12345()

不過後來被朋友更正說我的這個做法並不是真正的 curry,只是看似 curry 的效果罷了,所以晚上後來研究之後寫出了比較接近真正 curry 的 decorator:

# generic currying decorator

# right currying behavior

from functools import partial

"""
Curry decorator
"""
def curry(func, args_num=1, args_total=None):
    if not args_total: args_total = func.func_code.co_argcount
    def curried(arg1):
        next_func = partial(func, arg1)
        if args_num == args_total:
            return next_func()
        return curry(next_func, args_num+1, args_total)
    return curried


if __name__ == '__main__':
    @curry
    def add(a, b, c, d, e, f, g):
        return a + b + c + d + e + f + g

    add12 = add(1)(2)
    add1234 = add12(3)(4)
    add1234567 = add1234(5)(6)(7)
    print add1234567 # 28


爲什麼我們要用一個不是 functional language 的語言來寫 functional 的東西,你傲嬌喔?

Start small

我們當然可以用 Haskell、Erlang、Racket 來寫 funcitonal programming,不過對一個初學者來說,這中間轉換的門檻太大,很容易半途而廢,身爲一個常常在傳教的傳教士,我採用的戰術是「慢慢感染、荼毒」這些初心者,Python、JavaScript 這類語言都是很好的選擇,這些語言語法平易近人,很多人可能原本就在使用他了,它們可以選擇性的 functional,減少學習 functional programming 時可能會遇到的阻礙。

方便性

像我們平常習慣寫 Script,就會有些思考模式接近 scripting,但是常常遇到有些地方又是 functional 的寫法比較 concise,這時候用 Python 來寫就可以摸蛤蟆兼洗褲,該 scripting 的地方 scripting,該 functional 的地方 functinoal,像有時候用 Erlang 寫 escript 有時候也是有點懶阿 XD

comments powered by Disqus