Scala 中的函数式编程基础(一)
主要來自 Scala 語言發(fā)明人 Martin Odersky 教授的 Coursera 課程 《Functional Programming Principles in Scala》。
很久以前寫過一個非常簡單的 python lambda 函數(shù)博客,里頭有 filter,map,reduce等,是python中很有意思的部分,可以先看看。
另外酷殼網(wǎng)陳皓寫了一篇介紹函數(shù)式編程的博客,言簡意賅,對理解函數(shù)式編程很有幫助,非常值得一看。
Scala 本意是可伸展。它的設(shè)計哲學(xué)是:允許用戶通過定義感覺像原生語言支持一樣的易用庫去在他們需要的方向上改進(jìn)和發(fā)展語言——Scala allows users to grow and adapt the language in the directions they need by defining easy-to-use libraries that feel like native language support.。Scala 運(yùn)行在 Java 平臺上,可以與所有的 Java 庫無縫交互。
1. Function evaluations
Scala 是純粹的面向?qū)ο笫降木幊?#xff0c;所有的 value 都是一個對象。
Scala 是函數(shù)式的編程,它把每一個函數(shù)看做一個 value,函數(shù)即對象。
1.1 函數(shù)的副作用
純函數(shù)(Pure Function)是這樣一種函數(shù)——輸入輸出數(shù)據(jù)流全是顯式(Explicit)的。
顯式(Explicit)的意思是,函數(shù)與外界交換數(shù)據(jù)只有一個唯一渠道——參數(shù)和返回值;函數(shù)從函數(shù)外部接受的所有輸入信息都通過參數(shù)傳遞到該函數(shù)內(nèi)部;函數(shù)輸出到函數(shù)外部的所有信息都通過返回值傳遞到該函數(shù)外部。
隱式(Implicit)的意思是,函數(shù)通過參數(shù)和返回值以外的渠道,和外界進(jìn)行數(shù)據(jù)交換。比如,讀取全局變量,修改全局變量,都叫作以隱式的方式和外界進(jìn)行數(shù)據(jù)交換;比如,利用I/O API(輸入輸出系統(tǒng)函數(shù)庫)讀取配置文件,或者輸出到文件,打印到屏幕,都叫做隱式的方式和外界進(jìn)行數(shù)據(jù)交換。
Pure Function的好處主要有幾點(diǎn):
以上關(guān)于 pure function 的描述引用這篇博客。
另外一篇博客也介紹函數(shù)的副作用,推薦看看!
在函數(shù)式編程語言里面,函數(shù)是一等公民,這意味著:
- 像其他 value,可以在任何地方定義函數(shù),包括函數(shù)內(nèi)部
- 像其他 value,函數(shù)可以作為其他函數(shù)的輸入?yún)?shù)或者返回值
- 像其他 value,函數(shù)也有自己的操作符進(jìn)行組合等操作
1.2 參數(shù)調(diào)用的區(qū)別
scala 函數(shù)定義格式如下:
- call by value
遇到表達(dá)式就計算,scala 函數(shù)參數(shù)默認(rèn)進(jìn)入函數(shù)內(nèi)部之前計算出 value,再傳進(jìn)內(nèi)部,關(guān)鍵字?val?也是立即計算模式 - call by name
惰性求值,這是函數(shù)式編程里面一個非常重要的概念。要用到的時候才計算,可以用def fun(x:Int, y: => Int) = ...?中的?=>顯式調(diào)用。關(guān)鍵字?def?也是這種模式
舉個例子:
def loop: Int = loop // 定義一個死循環(huán),def 可以,val 不行 def constOne(x: Int, y: => Int) = 1 // 第一個參數(shù)x: call by value, 第二個參數(shù)y: call by name constOne(1+2, loop) // loop一直沒用,所以沒有計算,輸出1 constOne(loop, 1+2) // 遇到loop立即計算,陷入死循環(huán)1.3 牛頓法求平方根
- Scala 中遞歸函數(shù)需要寫返回值類型,非遞歸不一定要寫。
- 函數(shù)定義可以放在函數(shù)內(nèi)部,防止命名污染。
牛頓法的基本思路是遞歸,首先猜測為 1.0,如果誤差過大,則猜測值改為 guess 與 x / guess 的平均值。
object session {def abs(x: Double) = if (x>=0) x else (-x) def sqrt(x: Double) = {def sqrtIter(guess: Double): Double =if (isGoodEnough(guess)) guesselse sqrtIter(improve(guess))def isGoodEnough(guess: Double) =abs(guess * guess - x) / x < 0.001def improve(guess: Double) =(guess + x / guess) / 2sqrtIter(1.0)} sqrt(2.0) }1.4 尾遞歸
這篇博客推薦看看——遞歸與尾遞歸總結(jié)。
遞歸相對常用的算法如普通循環(huán)等,運(yùn)行效率較低。在遞歸調(diào)用的過程當(dāng)中系統(tǒng)為每一層的返回點(diǎn)、局部量等開辟了棧來存儲,因此遞歸次數(shù)過多容易造成棧溢出。
尾遞歸對應(yīng) imperative program(如c++)中的循環(huán)。 函數(shù)調(diào)用出現(xiàn)在調(diào)用者函數(shù)的尾部, 因為是尾部, 所以根本沒有必要去保存任何局部變量(需要保存的變量可以放在函數(shù)參數(shù)列表里)。它的棧是常數(shù),可復(fù)用,與循環(huán)一樣高效。
遞歸:
// 階乘函數(shù) def factorial(n: Int): Int =if (n == 0) 1 else n * factotial(n - 1)尾遞歸:
// 階乘函數(shù) def factorial(n: Int) = {def loop(acc: Int, n: Int): Int=if (n == 0) accelse loop(acc * n, n - 1)loop(1, n)}?
by:daniel-D from:http://www.cnblogs.com/daniel-D/總結(jié)
以上是生活随笔為你收集整理的Scala 中的函数式编程基础(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 配置redis禁用几个危险命令
- 下一篇: Apache Ignite(五):Ign