如何掌握函數式編程?


作為一個過來人 說幾句.

函數式編程並不難 但是它是一門冷門的技術,學習一門冷門的技術 回報比是很低的 學習它可能還沒有刷題找工作更有效率。同樣是因為一門冷門的技術 如果旁邊沒有有經驗的人指點的話 學習時間更長。所以如果你想真正掌握它的精髓的話 注意說得是很高層次的掌握不是像(functional programming in javascript 這種), 旁邊有非常經驗的人 或者 自己悟性比較好(比如top2姚班的人)或者 很小的時候就接觸編程了可以參考下我的經歷(年代久遠可能記憶有誤差).

我是08年大三在msra的時候接觸到fp 的當時 是微軟的 F#, 和很多人一樣覺得這東西很美,編程第一次覺得有樂趣(我當時還在學習wpf..) 於是我把當時所有能找到的關於F#的書都看了遍, 當時比較好的是 expert F# (apress 出版的)但是卡殼了,monad理解不了(F#叫computation expression) 還有continuation.

於是google了下monad的資料發現全是haskell的東西 所以開始學習haskell (注意因為我很早就使用emacs了 所以搭建工作環境是很方便的) 還是理解不了monad 於是就把mtl package里所有的 class type 手工抄寫了好幾遍 豁然開朗 學習haskell 是一個非常漫長的過程 當時讀過的書有real world haskell, haskell 的wiki, 還有很多很多haskell的論文, haskell的論文不是一般的難懂啊 因為很多論文裡面別說英文字母了 全是希臘字母啊 當然也有一些簡單的論文 比如walder的幾篇關於monad的 還有john huges的論文都比較好懂(關於arrow, quick check 之類的)

與此同時我還在尋找自己覺得最高效的編程語言 大四的時候因為受冰河的影響讀了幾本關於lisp宏的書, on lisp 和 paradigms of artificial intelligence in common lisp, let over lambda. 後來意識到宏雖好 但一切沒有類型的語言寫大型程序都是耍流氓 就忍著沒去了解clojure了。

後來研一 了 由於受宏的影響我就了解到metaocaml和camlp4 還有coq了 慢慢接觸到ocaml了 有一本好書推薦(the functional approach to programming). 後來我有上過當時清華的一個暑期學校專門講coq的。因為當時研究的熱情不減 所以就跟我再msra的導師harry 說自己想出國念programming language,於是導師很nice的答應了 並幫我推薦

注意到現在為止看上去我懂了很多了其實還是沒有入門, 因為沒有受到真正科班的訓練 沒有寫過大型fp程序, 或者說當時還是一個民科的水準

記得當時我只申請了幾所學校 有一所貌似還寄丟了 於是來到了賓大念phd. 導師是夫妻店都很nice, 經常周末去他們家和小孩下棋 。。

老闆娘算是haskell界的權威之一了, 當時跟著她學習了一學期 終於看haskell的形式化研究的論文沒有什麼壓力了 但是忽然發現自己跳到一個自己其實並不喜歡的東西裡面去了 因為全都是定理證明之類的 定理證明的問題有兩類:一類是這也能證明 另一類是這也需要證明。。

這一學期跟老闆娘還學了generic programming in haskell, 因為自己對ocaml也感興趣就port 到 ocaml里去了 用的是camlp4. 後來就慢慢接觸到ocaml 的編譯器裡面了。當時老闆娘也讓我去看看haskell的編譯器 但是haskell的編譯器實在編譯太慢了 興趣受到很大打擊。因為老闆是研究ML的 所以 就不跟老闆娘 跟老闆了。老闆鼓勵我把camlp4重寫一下 因為我自己之前研究過很長時間lisp了 然後ocaml的編譯器實在設計的簡單 思路清晰, 這次重寫對我的影響很大 因為camlp4算是ocaml裡面最複雜的軟體之一了,自己終於不是一個理論派了 有著大型軟體工程經驗

後來第二年現在的僱主需要一個ocaml expert, 然後老闆也覺得這是一個不錯的機會 就讓我走了。賓大的這兩年讓我從一個悟性不錯的民科變成了一個業內人士吧。所以要想學習冷門技術 旁邊有一個引路人 真的很重要。

對了 我現在天天寫javascript (ocaml 編譯成的 js)


發現是7月份答得,原來過了這麼久了。。。過來更新一下

關於感想補充的:

我現在覺得SICP是本好教材,但是也只是本好教材。

關於路線補充的:

入門的話,不管以後想走common lisp 路線,還是走scheme這條線

我都強烈推薦把 The little schemer 和 The seasoned schemer 認真看幾遍

(the reasoned schemer我還沒看,看完接著過來更新。。。)

如果可以只看描述就把函數寫出來的話最好,做不到的話至少要把代碼打下來,給兩個值運行一下。

然後可以同時寫個簡單的解釋器,可以從垠神那篇博客或者TLS第10章的例子開始,然後學到什麼就加什麼,比如letrec , letcc之類的

關於書籍補充的

屬於進階系列。。。

The Scheme Programming Language, 4th Edition

昨天才反應過來居然是

R. Kent Dybvig 寫的

The Scheme Programming Language, 4th Edition

作者開放的電子版

Essential of Programming Languages, 3rd Edition

Daniel P. Friedman 老爺子的。。。

以上所有書籍亞馬遜中國都有售,就是特別特別貴。。。

關於編程環境補充的:

寫著寫著就開始覺得mit-scheme不夠用了,然後我又習慣在emacs里,不想在外面單開個解釋器。

然後發現個東西

Geiser: Top

可以在emacs里連接racket

在部分系統里可能有個小問題

Setting Racket Geiser Emacs Path

------------------------------------以下是第一版------------------------------------------

拋磚引玉。Haskell 和Clojure自動跳過。。。沒用過。

掌握就是不斷的練習練習思考然後接著練習。

Scheme:

1.SICP Structure and Interpretation of Computer Programs

Mit 的 6.001 麻省理工學院「開放式課程網頁」 |
電機工程與計算機科學

上課視頻,講義,作業什麼的都全了。書後練習的話 我在看huangz的答案。

2.TLS The Little Schemer

我自己覺得看完SICP 前兩章跳到這本書,看完之後然後再回頭看剩下的感覺比較好。

3.當然我在扯淡

解釋器那篇比SICP的第四章簡潔多了。

http://4.schcme.org

Welcome to schemers.org!

如果要更深入一些的話,王垠在博客里給過一些。

然後IU的C311還有一個書單。C311/B521/A596 Programming Languages [Home]

Dan Friedman 老爺子還是很靠的住的。

GNU有個叫gulie GNU Guile (About Guile) 的玩意。

Common lisp:

參考 田春冰河 Chun Tian (binghe)的博客,我記得他給過書單,Paul Graham 寫的之類的。


名著類 - ajoo

所有想在常見的面向對象語言裡面使用函數式編程的技巧的,都得看這個


sicp入門 common lisp練手 clojure實用

clojure在jvm平台上非常棒的lisp實現。

common lisp好久不玩了。看過land of lisp 和pcl。

sicp確實不錯的。跟著書學一下 寫一下。就ok了。


做IU C311的作業

看programming languages:Application and Implementation


不清楚您的 Python 基礎是什麼樣的基礎。如果不是專業要深入的話,用 Python 完全足夠了,不需要涉及 Scheme。

Python 的話要會畫 Environment Diagram,理解 Lexical Frame 和 Dynamic Frame,High Order Function 的使用技巧,可以看些 Lambda Calculus 的書。如果你能用 Python 寫一個 Scheme 的 Interpretor 的話,那就算掌握骨架了。

給個好玩的吧,僅用 lambda,不允許使用 define,不允許使用 = 賦值,在一個表達式內,寫出一個能計算階乘的函數。

更難一點的還有用 lambda 及 filter 用一個表達式內寫出可以排序 Tuple 的快排。用 Tuple 是因為 Tuple 具有不可修改的良好特性。

其實語言不是問題,Functional Programming 難在轉換思路。值得思考的是,在我國大學不分專業全都跟著譚老爺子學習 C 語言的時候,國外很多大學的 CS 本科先學 Python。


能寫一個簡單的common lisp解釋器算是入門了。


這是個 Coursera 課程,用的是 scala:

Coursera.org

基本上理解函數編程:就是把輸入不斷用函數轉換 (transform) 、轉換、再轉換,直至得出結果。

用數學表達: y = f1 (f2 (f3 (.... fn(x)...)))

x 就是輸入,y 是輸出, f 是你應用 (apply) 的各種函數。

例如在 Lisp 中, car(list) 的結果就是給出序列 list 的第一個元素。 在其他語言都有同一個函數,名稱不同而已。

PS: 開始時毋須看厚厚的書,在網上快速地學會某一語言的基本運算 (通常需時一兩天左右) 便可以開始編程了 :)


Lisp in Small Parts 這個網站還沒有人提到,這是一個人教他十幾歲女兒學lisp的教程。這種教程有一個問題,它是教人編程的,不一定是教人lisp的,如果你會編程,不太會lisp,可能就不是很有針對性。就像我想學javascrip,看哪種以js為例教人編程的書、教程,就不是很得要領,後來偶然看到《悟透javascrip》,就覺得幫助很大。


如果想學習中不枯燥,所見即所得,那就直接學F#


你要注意一下——函數式編程會有很多和命令式編程不同的東西,也有一些概念(例如函數)在函數式編程和命令式編程里截然不同。

想學函數式編程,我建議學習scheme。因為這種語言很簡單,也能讓你快速的理解函數式編程中的很多概念。至於學scheme需要看什麼書嗎~,當然推薦SICP嘍(這本書在函數式編程界可是被譽為《聖經》的!)!

關於scheme的社區嘛~,你可以看看scheme小組,同時我還力薦你看看王垠的博客!並關注的他的知乎!

如果你想做點小項目的話,你可以看看鮮肉網。如果你的scheme水平已經很高,你就可以看看Take Action
- GNU Project。


以前用C++,現在寫Erlang,覺得真的語言的區別挺大,但是對於實現功能來說,都是一個思想。函數式語言,就是覺得模式匹配挺爽的,寫起來很優雅,就是不知道底層是咋實現的。別的,變數不可變,有時候挺蛋疼的,老是會出現X1、X2這樣的變數名。如果題主真的是想學函數式編程,何不找本書來看看,來這問是沒用的。


推薦你一個軟體 txr 。怪異但強大的文本正則處理工具。使用lisp 方言,致力於文本提取。


用Emacs Lisp寫插件啊


推薦閱讀:

以函數編程語言作為入門的編程語言有什麼好處?
聲明式編程和命令式編程有什麼區別?
大家對於徐昊的《對象已死?》這篇文章怎麼看?

TAG:編程語言 | 函數式編程 |