【Scala】高階函數(shù)和柯里化

高階函數(shù)

在數(shù)學(xué)和計(jì)算機(jī)科學(xué)中纯出,高階函數(shù)是至少滿足下列一個(gè)條件的函數(shù):

- 接受一個(gè)或多個(gè)函數(shù)作為輸入
- 輸出一個(gè)函數(shù)

在數(shù)學(xué)中它們也叫做算子(運(yùn)算符)或泛函。微積分中的導(dǎo)數(shù)就是常見的例子敷燎,因?yàn)樗成湟粋€(gè)函數(shù)到另一個(gè)函數(shù)暂筝。

高階函數(shù)的例子

假設(shè)有一個(gè)函數(shù)對(duì)給定兩個(gè)數(shù)區(qū)間中的所有整數(shù)求和:

def sumInts(a: Int, b: Int): Int = 
  if(a > b) 0 else a + sumInts(a + 1, b)

如果現(xiàn)在要求連續(xù)整數(shù)的平方和:

def square(x: Int): Int = x * x
def sumSquares(a: Int, b: Int): Int = 
  if(a > b) 0 else square(a) + sumSquares(a + 1, b)

如果要計(jì)算2的冪次的和:

def powerOfTwo(x: Int): Int = if(x == 0) 1 else 2 * powerOfTwo(x-1)
def sumPowersOfTwo(a: Int, b: Int): Int = 
  if(a > b) 0 else powerOfTwo(a) + sumPowersOfTwo(a+1, b)

上面的函數(shù)都是從a到b的f(n)的累加形式,我們可以抽取這些函數(shù)中共同的部分重新編寫函數(shù)sum硬贯,其中定義的f作為一個(gè)參數(shù)傳入到高階函數(shù)sum中:

def sum(f: Int => Int, a: Int, b: Int): Int = 
  if(a > b) 0 else f(a) + sum(f, a+1, b)

def id(x: Int): Int = x
def square(x: Int): Int = x * x
def powerOfTwo(x: Int): Int = if(x == 0) 1 else 2 * powerOfTwo(x-1)

def sumInts(a: Int, b: Int): Int = sum(id, a, b)
def sumSquared(a: Int, b: Int): Int = sum(square, a, b)
def sumPowersOfTwo(a: Int, b: Int): Int = sum(powerOfTwo, a, b)

有用的高階函數(shù)

map方法將一個(gè)函數(shù)應(yīng)用到某個(gè)集合的所有元素并返回結(jié)果焕襟;foreach將函數(shù)應(yīng)用到每個(gè)元素。

//打印三角形
scala> (1 to 9).map("^" * _).foreach(println _)
^
^^
^^^
^^^^
^^^^^
^^^^^^
^^^^^^^
^^^^^^^^
^^^^^^^^^

filter方法輸出所有匹配某個(gè)特定條件的元素:

scala> (1 to 9).filter(_ % 2 == 0)
res14: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8)

可以通過練習(xí)使用Scala集合庫中的一些常用的接受函數(shù)參數(shù)的方法來熟悉高階函數(shù)饭豹。

柯里化

柯里化(Currying)指的是將原來接受兩個(gè)參數(shù)的函數(shù)變成新的接受一個(gè)參數(shù)的函數(shù)的過程胧洒。新的函數(shù)返回一個(gè)以原有第二個(gè)參數(shù)為參數(shù)的函數(shù)。

返回函數(shù)的函數(shù)

在上面高階函數(shù)的例子中墨状,我們通過def sumInts(a: Int, b: Int): Int = sum(x => x, a, b)def sumSquared(a: Int, b: Int): Int = sum(x => x*x, a, b)來定義新的函數(shù)菲饼,上面這兩個(gè)函數(shù)每次都要傳入a和b兩個(gè)參數(shù)到sum函數(shù)中肾砂,我們能否簡化這些參數(shù)使得函數(shù)定義更簡單呢?
我們可以通過返回函數(shù)的函數(shù)來簡化參數(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ù)
def sumInts = sum(x => x)
def sumSquared = sum(x => x * x)
def sumPowersOfTwo = sum(powerOfTwo)

多個(gè)參數(shù)列表

根據(jù)上面的例子镐确,我們能不能更加簡化包吝,省去sumIntssumSquared源葫、sumPowersOfTwo這幾個(gè)中間函數(shù)的形式呢诗越?
通過sum(square)(1, 10)函數(shù)來替代sumSquared函數(shù)。
一般情況息堂,這類函數(shù)的左結(jié)合的:sum(square)(1, 10) == (sum(square))(1, 10)嚷狞。

我們可以這樣定義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ù)編寫更加簡潔。

一般的荣堰,多參數(shù)函數(shù)定義為def f(args1)...(argsn) = E,
當(dāng)n > 1時(shí)床未,等同于def f(args1)...(args n-1) = {def g(argsn) = E; g}或者def f(args1)...(args n-1) = (argsn => E)
如果重復(fù)這個(gè)過程n次振坚,得到def f = (args1 => (args2 => ... (argsn => E) ) )薇搁。
這種函數(shù)定義稱為柯里化(Currying)。

轉(zhuǎn)載請(qǐng)注明作者Jason Ding及其出處
GitCafe博客主頁(http://jasonding1354.gitcafe.io/)
Github博客主頁(http://jasonding1354.github.io/)
CSDN博客(http://blog.csdn.net/jasonding1354)
簡書主頁(http://www.reibang.com/users/2bd9b48f6ea8/latest_articles)
百度搜索jasonding1354進(jìn)入我的博客主頁

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末渡八,一起剝皮案震驚了整個(gè)濱河市啃洋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屎鳍,老刑警劉巖宏娄,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異哥艇,居然都是意外死亡绝编,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門貌踏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來十饥,“玉大人,你說我怎么就攤上這事祖乳《憾拢” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵眷昆,是天一觀的道長蜒秤。 經(jīng)常有香客問我,道長亚斋,這世上最難降的妖魔是什么作媚? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮帅刊,結(jié)果婚禮上纸泡,老公的妹妹穿的比我還像新娘。我一直安慰自己赖瞒,他們只是感情好女揭,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布蚤假。 她就那樣靜靜地躺著,像睡著了一般吧兔。 火紅的嫁衣襯著肌膚如雪磷仰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天境蔼,我揣著相機(jī)與錄音灶平,去河邊找鬼。 笑死欧穴,一個(gè)胖子當(dāng)著我的面吹牛民逼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涮帘,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼拼苍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了调缨?” 一聲冷哼從身側(cè)響起疮鲫,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弦叶,沒想到半個(gè)月后俊犯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伤哺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年燕侠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片立莉。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绢彤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜓耻,到底是詐尸還是另有隱情茫舶,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布刹淌,位于F島的核電站饶氏,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏有勾。R本人自食惡果不足惜疹启,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蔼卡。 院中可真熱鬧皮仁,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喝峦。三九已至势誊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谣蠢,已是汗流浹背粟耻。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留眉踱,地道東北人挤忙。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像谈喳,于是被迫代替她去往敵國和親册烈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容