深入理解Scala函數(shù)式編程過(guò)程
深入理解Scala函數(shù)式編程過(guò)程
我們馬上開(kāi)始一段變態(tài)的過(guò)程
如果要求立方和,可以這么做
35 * 35 * 35 68 * 68 * 68
沒(méi)毛病,抽象一點(diǎn)兒,寫(xiě)個(gè)函數(shù):
def cube(n: Int) = n * n * n cube(35) cube(68)
省事兒了,如果求1到10的立方和,OK,寫(xiě)個(gè)遞歸
def cube(n: Int) = n * n * n def sumCube(a: Int, b: Int): Int = if (a > b) 0 else cube(a) + sumCube(a + 1, b) sumCube(1, 10)
變態(tài)一點(diǎn)兒,立方和,平方和,階乘和,依舊寫(xiě)出它們的函數(shù)并且依次計(jì)算沒(méi)毛病
def cube(n: Int) = n * n * n def id(n: Int) = n def square(n : Int) = n * n def fact(n: Int): Int = if (n == 0) 1 else n * fact(n - 1) def sumCube(a: Int, b: Int): Int = if (a > b) 0 else cube(a) + sumCube(a + 1, b) def sumSquare(a: Int, b: Int): Int = if(a > b) 0 else square(a) + sumSquare(a + 1, b) def sumFact(a: Int, b: Int): Int = if (a > b) 0 else fact(a) + sumFact(a + 1, b) def sumInt(a: Int, b: Int): Int = if(a > b) 0 else id(a) + sumInt(a + 1, b) sumCube(1, 10) sumInt(1, 10) sumSquare(1, 10) sumFact(1, 10)
然后你發(fā)現(xiàn),你已經(jīng)寫(xiě)了一堆同樣邏輯的if else,看起來(lái)不奇怪么,這種無(wú)腦的操作當(dāng)然要避免:
我們要把這些函數(shù)名不同但是處理邏輯相同的渣渣都封裝到一個(gè)函數(shù)中,并且這個(gè)函數(shù)將作為參數(shù)賦值到高階函數(shù)中,運(yùn)行的結(jié)果只跟傳入的參數(shù)類(lèi)型有關(guān)系,也就是把cube,square,fact,泛化成一個(gè)f
def cube(n: Int) = n * n * n def id(n: Int) = n def square(n : Int) = n * n def fact(n: Int): Int = if (n == 0) 1 else n * fact(n - 1) //高階函數(shù) def sum(f: Int=>Int, a:Int, b:Int): Int = if(a>b) 0 else f(a)+sum(f, a+1, b) // 使用高階函數(shù)重新定義求和函數(shù) def sumCube(a: Int, b: Int): Int = sum(cube, a, b) def sumSquare(a: Int, b: Int): Int = sum(square, a, b) def sumFact(a: Int, b: Int): Int = sum(fact, a, b) def sumInt(a: Int, b: Int): Int = sum(id, a, b) sumCube(1, 10) sumInt(1, 10) sumSquare(1, 10) sumFact(1, 10)
但是這樣寫(xiě),還有個(gè)問(wèn)題,就是前面定義了一堆cube,id的初始定義,后面還要繼續(xù)定義,實(shí)際上就是套了一層包裝,不要了,去掉,使用匿名函數(shù)的功能來(lái)將調(diào)用進(jìn)一步簡(jiǎn)化。多數(shù)情況下,我們關(guān)心的是高階函數(shù),而不是作為參數(shù)傳入的函數(shù),所以為其單獨(dú)定義一個(gè)函數(shù)是沒(méi)有必要的。值得稱(chēng)贊的是 Scala 中定義匿名函數(shù)的語(yǔ)法很簡(jiǎn)單,箭頭左邊是參數(shù)列表,右邊是函數(shù)體,參數(shù)的類(lèi)型是可省略的,Scala 的類(lèi)型推測(cè)系統(tǒng)會(huì)推測(cè)出參數(shù)的類(lèi)型。使用匿名函數(shù)后,我們的代碼變得更簡(jiǎn)潔了:
//保留邏輯較為復(fù)雜的函數(shù) def fact(n: Int): Int = if (n == 0) 1 else n * fact(n - 1) def sum(f: Int => Int, a: Int, b: Int): Int = if (a > b) 0 else f(a) + sum(f, a + 1, b) // 使用高階函數(shù)重新定義求和函數(shù) def sumCube(a: Int, b: Int): Int = sum(x => x * x * x, a, b) def sumSquare(a: Int, b: Int): Int = sum(x => x * x, a, b) def sumFact(a: Int, b: Int): Int = sum(fact, a, b) def sumInt(a: Int, b: Int): Int = sum(x => x, a, b) sumCube(1, 10) sumInt(1, 10) sumSquare(1, 10) sumFact(1, 10)
寫(xiě)到這里問(wèn)題解決的差不多了,但是我們仔細(xì)想想,函數(shù)式編程的真諦,一個(gè)輸入到另一個(gè)輸出,而不是像這樣兩個(gè)參數(shù)傳來(lái)傳去,看起來(lái)很麻煩,于是乎
def fact(n: Int): Int = if (n == 0) 1 else n * fact(n - 1) // 高階函數(shù) def sum(f: Int => Int): (Int, Int) => Int = { def sumF(a: Int, b: Int): Int = if (a > b) 0 else f(a) + sumF(a + 1, b) sumF } // 使用高階函數(shù)重新定義求和函數(shù) def sumCube: Int = sum(x => x * x * x) def sumSquare: Int = sum(x => x * x) def sumFact: Int = sum(fact) def sumInt: Int = sum(x => x) // 這些函數(shù)使用起來(lái)還和原來(lái)一樣 ! sumCube(1, 10) sumInt(1, 10) sumSquare(1, 10) sumFact(1, 10)
實(shí)際上這個(gè)時(shí)候sum里面?zhèn)魅氲囊呀?jīng)是匿名函數(shù)了,類(lèi)似于g(f(x))里面的f(x), 你還需要去調(diào)用那個(gè)f(x)而不是去腦補(bǔ)運(yùn)算.
我們?cè)賮?lái)開(kāi)一下腦洞,既然sum返回的是一個(gè)函數(shù),我們可以直接使用這些函數(shù),沒(méi)有必要再重復(fù)寫(xiě)一遍調(diào)用命令了,sumCube(1, 10) 類(lèi)的語(yǔ)句可以省去不要了。
def fact(n: Int): Int = if (n == 0) 1 else n * fact(n - 1) // 高階函數(shù) def sum(f: Int => Int): (Int, Int) => Int = { def sumF(a: Int, b: Int): Int = if (a > b) 0 else f(a) + sumF(a + 1, b) sumF } // 直接調(diào)用高階函數(shù) ! sum(x => x * x * x) (1, 10) //=> sumCube(1, 10) sum(x => x) (1, 10) //=> sumInt(1, 10) sum(x => x * x) (1, 10) //=> sumSquare(1, 10) sum(fact) (1, 10) //=> sumFact(1, 10)
最后我們還可以使用高階函數(shù)的語(yǔ)法糖來(lái)進(jìn)一步優(yōu)化這段代碼:
// 沒(méi)使用語(yǔ)法糖的 sum 函數(shù) def sum(f: Int => Int): (Int, Int): Int = { def sumF(a: Int, b: Int): Int = if (a > b) 0 else f(a) + sumF(a + 1, b) sumF } // 使用語(yǔ)法糖后的 sum 函數(shù) def sum(f: Int => Int)(a: Int, b: Int): Int = if (a > b) 0 else f(a) + sum(f)(a + 1, b)
我反而覺(jué)得用語(yǔ)法糖更容易理解一點(diǎn),更傾向于我們學(xué)的數(shù)學(xué)語(yǔ)言。
讀者可能會(huì)問(wèn):我們把原來(lái)的sum函數(shù)轉(zhuǎn)化成這樣的形式,好處在哪里?答案是我們獲得了更多的可能性,比如剛開(kāi)始求和的上下限還沒(méi)確定,我們可以在程序中把一個(gè)函數(shù)傳給sum, sum(fact)完全是一個(gè)合法的表達(dá)式,待后續(xù)上下限確定下來(lái)時(shí),再把另外兩個(gè)參數(shù)傳進(jìn)來(lái)。對(duì)于 sum 函數(shù),我們還可以更進(jìn)一步,把 a,b 參數(shù)再轉(zhuǎn)化一下,這樣 sum 函數(shù)就變成了這樣一個(gè)函數(shù):它每次只能接收一個(gè)參數(shù),然后返回另一個(gè)接收一個(gè)參數(shù)的函數(shù),調(diào)用后,又返回一個(gè)只接收一個(gè)參數(shù)的函數(shù)。這就是傳說(shuō)中的柯里化,多么完美的形式!在現(xiàn)實(shí)世界中,的確有這樣一門(mén)函數(shù)式編程語(yǔ)言,那就是 Haskell,在 Haskell 中,所有的函數(shù)都是柯里化的,即所有的函數(shù)只接收一個(gè)參數(shù)!
// 柯里化后的 sum 函數(shù) def sum(f: Int => Int)(a: Int) (b: Int): Int = if (a > b) 0 else f(a) + sum(f)(a + 1)(b) // 使用柯里化后的高階函數(shù) ! sum(x => x * x * x)(1)(10) //=> sumCube(1, 10) sum(x => x)(1)(10) //=> sumInt(1, 10)
如有疑問(wèn)請(qǐng)留言或者到本站社區(qū)交流討論,感謝閱讀希望能幫助到大家,謝謝大家對(duì)本站的支持!
欄 目:Scala
下一篇:淺談Scala的Class、Object和Apply()方法
本文標(biāo)題:深入理解Scala函數(shù)式編程過(guò)程
本文地址:http://mengdiqiu.com.cn/a1/Scala/12003.html
您可能感興趣的文章
- 01-11php下關(guān)于Cannot use a scalar value as an array的解決辦法
- 01-11PHP警告Cannot use a scalar value as an array的解決方法
- 01-11Windows7下安裝Scala 2.9.2教程
- 01-11淺談Scala的Class、Object和Apply()方法
- 01-11Scala基礎(chǔ)簡(jiǎn)介及代碼示例
- 01-11Scala安裝及環(huán)境圖文配置教程
- 01-11利用Gradle如何構(gòu)建scala多模塊工程的步驟詳解
- 01-11linux下搭建scala環(huán)境并寫(xiě)個(gè)簡(jiǎn)單的scala程序
- 01-11Scala的文件讀寫(xiě)操作與正則表達(dá)式
- 01-11詳解如何使用Spark和Scala分析Apache訪問(wèn)日志


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-11php下關(guān)于Cannot use a scalar value as an ar
- 01-11PHP警告Cannot use a scalar value as an array的
- 01-11Windows7下安裝Scala 2.9.2教程
- 01-11淺談Scala的Class、Object和Apply()方法
- 01-11深入理解Scala函數(shù)式編程過(guò)程
- 01-11Scala基礎(chǔ)簡(jiǎn)介及代碼示例
- 01-11Scala安裝及環(huán)境圖文配置教程
- 01-11linux下搭建scala環(huán)境并寫(xiě)個(gè)簡(jiǎn)單的sca
- 01-11利用Gradle如何構(gòu)建scala多模塊工程的步
- 01-11Scala的文件讀寫(xiě)操作與正則表達(dá)式
隨機(jī)閱讀
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10C#中split用法實(shí)例總結(jié)
- 04-02jquery與jsp,用jquery
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-10delphi制作wav文件的方法