這篇文章從下面幾個方面學習函數式編程:
1、數學公式和函數式編程有什么關系
舉個簡單例子吧,數學中有一個概念叫做映射(y=f(x)),說的通俗一點就是函數啦。而最熟悉的應該就是二次函數(拋物線y=a*x*x+b*x+c)
現在coding實現求拋物線上某一點的值,我們知道a,b,c是參數,x是自變量,y是因變量,如果是以前,我也許會這么實現(為了紀念我許久未寫的c++,還是用c++來寫一下)
double getParabola(double a,double b,double c,double x) { return a*x*x+b*x+c; }
問題一、給定拋物線,求x=2,x=3,x=4時的值,就是下面的做法了
resultA = getParabola(a,b,c,2) resultB = getParabola(a,b,c,2) resultC = getParabola(a,b,c,2)
這在程序中,是很正常的做法。但是,如果從數學的角度來看,有沒有辦法變得符合數學公式思維呢?以下是我的另外一種實現(這里用go來實現哈,因為c++我知道怎么寫),
func getParabola(aa,bb,cc float32){ var a = aa var b = bb var c = cc a := func(x float32) { return a*x*x+b*x+c } return a }
然后,同樣是對于問題一,解決方案如下
parabola := getParabola(a,b,c) resultA := parabola(2) resultB := parabola(3) resultC := parabola(4)
是不是跟求函數值一樣?所以,數學關系在函數式編程中得到了很好的體現。
2、函數式編程有什么特點,go支持了哪些概念
函數式編程有三大特性
1、變量的不可變性: 變量一經賦值不可改變。如果需要改變,則必須復制出去,然后修改。 go中,string變量一經賦值,不可以像c++那樣,c[2]='a'這樣的修改,而是要顯式轉化為[]byte,然后進行修改。但是已經是另外一塊內存了。
2、函數式一等公民: 函數也是變量,可以作為參數,返回值等在程序中進行傳遞。 這個特性,c++和go應該都是支持的。
3、尾遞歸:遞歸的概念在斐波那契數列的時候,就學習過了。如果遞歸很深的話,堆??赡軙?,并導致性能大幅度下降。而尾遞歸優化技術,編譯器如果支持的話,可以在每次遞歸時重用stack(尾遞歸表示遞歸調用發生在最后一步,這個時候,之前的結果都作為參數傳遞給最后一步的調用,所以之前的狀態就沒有任何作用了,所以可以重用stack)。
函數式編程常用技術
1、map&reduce&filter
map用于對每一個輸入,調用同一個函數,產生一個輸出,比如c++中的for_each,hadoop里面的map,python的map等。
reduce用于對每一個輸入,加上上一個輸出,得到下一個輸出,比如python和hadoop中的reduce,
filter用于做過濾,比如c++的count_if等。
2、遞歸
3、pipeline
把函數實例放到一個數組或是列表中,然后把數據傳給這個action list,輸入順序地被各個函數所操作(意思是每一個函數的輸出,作為另外一個函數的輸入,數據是流動的,計算是固定的,類似storm的概念),最終得到我們想要的結果。
4、其他(有待進一步學習)
3、函數式編程與運行效率
函數式編程最重要的一個概念就是函數式一等公民,函數跟變量是一樣的??梢宰鳛閰?,返回值等。不贊成使用賦值語句,所以比較多的使用遞歸,所以函數式編程效率肯定會比較低。
最近我用的比較多的是閉包,閉包的概念就是一個環境(一個或多個變量)加上一個函數,每一次對閉包表達式求值,都得到一個隔離的結果,這跟普通函數是不一樣的,普通函數就是一段可執行的代碼,只要入口確定了,調用的位置也就確定了。舉個例子,上面拋物線的例子,調用
a:=getParabola(0.2,0.1,0.3) b:=getParabola(0.1,0.1,0.4)
得到的是兩條拋物線。之所以我覺得效率會降低,是因為閉包本身就是一個求值賦值的過程,涉及到變量的創建銷毀。當然,我沒有實際去測試性能。如果后續發行server效率降低,也許這是一個需要考慮的地方。
以上就是從go語言閉包談函數式編程的詳細內容,更多請關注億速云其它相關文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。