承接上文回複中的內容,先說明一下:我這將近兩年碰到任何問題都會先嘗試尋找FP的思路(而不僅僅是形式)解決。無論語言是C++、C#、Python、JS,無論目標的特點是什麼樣。當然可能有人就會說“你在不適合FP的地方如何如何...”,但是我採取這樣的策略,正是為了搞清楚FP在思路和形式兩方面上的適用範圍。
其中一部分問題的解決特別順理成章,同時設計和實現確實體現出FP抽象方式的特點;還有一部分情況如果仔細掂量,就會發現和使用命令式下子方法論僅僅在形式上有所區別。這兩部分無論哪種,就像腦袋說的使用OO作為工具也同樣可行,僅僅是舒適度有差異。
但總有一部分情況,最終感到FP不那麼合適而必須退回到一個命令式的設計。這一類情況即便在JS這樣還算原生支援FP的語言中,也會感到如果採用FP方式去設計,無論從思路還是在形式上都有太多讓人彆扭的地方(相對於用OO代替FP僅僅是不那麼舒服)。
從熟悉命令式的程式員的角度出發,這個問題我想不在於我作為標本是到底是有一定FP功底了還是略知皮毛。我想大多數命令式起家並且長期使用命令式語言,但是對FP感興趣的朋友,至少在這小兩年內,一般來說也不會比我更有這樣的空閑時間和自由度的在實際問題上去嘗試了。
另一方面,我也不敢說我對FP的掌握夠了,主要是我不是在和比如陳貓老兄一塊工作,這使得我碰見一些我認為FP極端不好處理的情形時,不知道其他人是不是也沒有這方面的思路。但我的主觀感受就是這樣:存在一大類問題,如果用純FP去解決,實在是要繞太多彎子。
我的自我感覺是,這些問題裡有一些可能是我的FP功力不夠所以沒找到正確的方法,但絕對有一些問題是因為FP本身的不適用(關鍵在於以某一視角看待問題的切入角度)所造成的;而命令式風格下所產生的思路,這種“不適用”的情況較FP要少。
比如LR(k)演算法,如果用比較純的FP思路並採取相應的形式實現,能像命令式那麼舒服嗎?但是相反的,LL(k)的遞迴下降實現(即可以是純FP也可以不是),就很容易被修改為使用命令式下的預測性分析法實現;同時即便是以命令式的思路實現的遞迴下降法也要更容易一些。
另一個例子是正則的自動機使用FP的思路還是比較好處理的,可能的一個重點是圍繞五元組中的delta函數(因為它是最難處理的)展開的設計;而兩個語言的串連、並、閉包,都可以求一個新的delta函數。如果僅僅實現教科書中的內容,這還是很順利的。
但是圍繞這個方式進行更多的工作的時候,我感覺在很多(進一步的)方面會受到制肘。反過來使用一組對象表示圖中的元素雖然也會讓一個解決具體問題的自動機產生不少冗餘,可總體上還是要比FP方式更加直觀、也容易進行各種各樣的調整和修改。
更普遍的如我寫的一些JS組件,這些組件從命令式的角度來看將會使用大量的中間資料結構和狀態。轉換到純FP風格,也許要求有一套monad的架構(為了效率),或者靠不斷產生新的計算結果(無論是對象還是函數)。一旦產生高一個層次的組織需要,如果僅僅使用FP範疇內的概念就會麻煩許多。
最終一個項目裡還是既有FP又有OO,但是在介面處如何保證風格的過渡,讓整個項目顯得比較統一,又是需要下一定功夫的。(原來和腦袋也討論過)
在這些方面,不只是我這樣唱衰的人好好使用過沒有,認為命令式程式員學習FP利大於弊的同志們,你們的經驗又是什麼樣的?很遺憾社區裡也缺乏這樣的交流,這使得對比而言FP的學習效率更差一些,也是FP的學習變得*性價比*很低的一個原因(上一篇文章沒有提到)。
關於SICP所傳授的抽象思維,這個其實在上一篇文章中也不是完全沒有涉及。當時我的意思是,同樣(或者說在效果上等價的)的抽象思維,通過任何一種命令式下面的子風格方法論,也是可以逐漸掌握的,沒有必要說非學習什麼思路不可,尤其是考慮到時間上的花銷。
尤其是問一下這個問題:某一種抽象就是非掌握不可嗎?
“且想象一個多面體是空心的,其表面由薄橡膠製成。我們若切去一面,便可使餘下的表面平鋪展開於一個平面上而不撕破它....”
上面的思想來自於柯西[1813a]對歐拉多面體猜想的證明。
在這裡引用它不是為了故弄玄虛,而是為了說明,對人們(即便是那些讓人高山仰止的傢伙)尋找思路及表述該思路有益的過程,很大程度上是抽離於各種層次的抽象工具的。而SICP等教科書所講授的方式方法,實則是太具體了,僅僅是若干工具中的一種。
我並不是反對FP或者什麼(比如通過SICP學習某些抽象方式),誰用FP舒服誰就用(包括我自己),關鍵是走一趟我這樣的學習與實踐的過程值不值。如果一個人比我有更強的能力,或者無論什麼原因(內在的外在的)有信心用較小的投入獲得足夠的收益,當然可以學習FP。
我的結論僅僅像winter-cn替我總結的那樣:無論是為了更好的解決問題還是繼續提高自身能力,都應避免盲目求助於某一種尚未掌握的、並非不可替代的特定抽象工具的學習。