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