標籤:
函數式編程成了現在編程圈裡越來越火的話題。我第一次聽說函數式編程是在編譯原理課上,那位巨牛逼的年輕老師用普林斯頓大學的教程向我們簡單介紹了ML語言,那時候編程和數學基礎都巨薄弱的我對“函數”兩字產生了極大的恐懼,對於ML的文法完全無法理解。第一次意識到函數式編程是在網上哪篇文章裡看到js的函數式編程能力(現在這種文章到處都是),我才發現我最常用的語言原來有這巨牛逼的能力,然後就沾沾自喜的以為自己就是函數式編程的程式員了。
呵呵,挺傻逼的。
js極度靈活,的確具有函數式編程的能力,但不是說寫個內建函式,參數裡傳個函數或者返回個函數就是函數式編程了,這隻是函數式編程的最低要求,所謂函數是一等公民。
後來學了一些clojure知道了還有個函數純不純的問題。
後來學了一點haskell知道了為函數式編程設計的語言調用函數是可以多麼的優雅!
今天說的是純函數,優雅明天說吧。
純函數就是不會對外界產生影響的函數,這個外界不光是程式外界,而是函數的外界。所以haskell沒有變數。一開始知道這個概念的時候感覺很恐怖。沒有變數!!!那我豈不是沒有地方儲存我程式運行到每一步的結果了嗎?比如我有個person,他age++了,如果這個person不是變數,那連age都沒法++。的確,純函數裡,你給函數一個29歲的人,他會返回給你一個30歲的人,原來29歲的人還在那。這不科學啊,怎麼平白無故多了個人呢!好吧,我要說,純函數語言都不是物件導向的,就不要那那麼具象的思維來思考了。可以怎麼想,30歲的我已經不是29歲的我了。。。很滄桑的解釋 -_-!
我想,函數式編程不是那麼容易被接受就是因為它抽象。不管你是人也好是木頭也好,對函數來說就是一個待加工的原件,函數負責產生一個新的成品,還不影響原來的,買一贈一不好嗎?
那這有什麼好處呢?拿haskell最得意的話來說,安全。你永遠無法改變一個已經存在的值,就意味著這個值可以在任何時候被你安全的使用,還可以被任何人安全的使用,這不就是並發裡面最難以解決的問題嗎。什麼這鎖那鎖呀,既然沒有變數,就不用鎖了。暫且不說並發(作為js程式員,還真沒法深入說並發),就說寫自己的線性程式,經常會發生的錯誤是一個值已經被改變了,但是你沒有意識到,還按照原來的方式去使用它,這種問題完全可以避免了,你要使用原來的值就是原來的值,要使用新值一定是通過一個函數加工過的值。
再怎麼純的函數式程式設計語言,還是要跟外界打交道的,要不然這個語言就沒有存在的意義了。純函數的語言會把不純的地方單拎出來,一股腦的給你汙染外界,而不是不停的汙染外界,這樣你就會更明白對外界做了什麼。
舉個例子對比一下。用jQuery進行dom操作,我最喜歡它的鏈式文法,query出來一個dom對象就開始使勁改變它,點一次變一點,.addClass一下加了個類名,.css一下變了個樣式。。。函數式編程肯定不會這樣,它一定會是拿到原來的dom對象,通過一串函數的加工,每次加工的結果是下一次加工的原料,而每次加工的結果都不對外界產生影響(這個結果是一個沒有掛到頁面上的東西),直到拿到最後一次加工的結果,才鄭重的真正操作dom替換原來的元素,最可能的方法是直接寫innerHTML。
嗯。。。不過這是我猜的,因為目前我還從來沒用純函數程式設計語言寫過web指令碼。但是這種語言是存在的,比如ELM,它是一種和Haskell文法很像的最終產生js、css和html代碼的語言,它用到了一種叫做Virtual DOM的技術,原理就是不直接操作dom而是叫做虛擬dom的資料,這個資料當然不會直接改變dom(所以不直接改變它而是每次調用函數產生一個新的virtual dom是完全可以的),當需要真的改變dom的時候,系統會比較一下前後dom的最小差異,然後進行最小的修改,所以效能也是杠杠的。怎麼樣,這很貼合純函數編程的思路吧?
扯一扯純函數