摘要:組合的概念是非常直觀的,并不是函數(shù)式編程獨有的,在我們生活中或者前端開發(fā)中處處可見。其實我們函數(shù)式編程里面的組合也是類似,函數(shù)組合就是一種將已被分解的簡單任務(wù)組織成復(fù)雜的整體過程。在函數(shù)式編程的世界中,有這樣一種很流行的編程風格。
JavaScript函數(shù)式編程,真香之認識函數(shù)式編程(一)
該系列文章不是針對前端新手,需要有一定的編程經(jīng)驗,而且了解 JavaScript 里面作用域,閉包等概念組合函數(shù)
組合是一種為軟件的行為,進行清晰建模的一種簡單、優(yōu)雅而富于表現(xiàn)力的方式。通過組合小的、確定性的函數(shù),來創(chuàng)建更大的軟件組件和功能的過程,會生成更容易組織、理解、調(diào)試、擴展、測試和維護的軟件。
對于組合,我覺得是函數(shù)式編程里面最精髓的地方之一,所以我迫不及待的把這個概念拿出來先介紹,因為在整個學(xué)習(xí)函數(shù)式編程里,所遇到的基本上都是以組合的方式來編寫代碼,這也是改變你從一個面向?qū)ο?,或者結(jié)構(gòu)化編程思想的一個關(guān)鍵點。
我這里也不去證明組合比繼承好,也不說組合的方式寫代碼有多好,我希望你看了這篇文章能知道以組合的方式去抽象代碼,這會擴展你的視野,在你想重構(gòu)你的代碼,或者想寫出更易于維護的代碼的時候,提供一種思路。
組合的概念是非常直觀的,并不是函數(shù)式編程獨有的,在我們生活中或者前端開發(fā)中處處可見。
比如我們現(xiàn)在流行的 SPA (單頁面應(yīng)用),都會有組件的概念,為什么要有組件的概念呢,因為它的目的就是想讓你把一些通用的功能或者元素組合抽象成可重用的組件,就算不通用,你在構(gòu)建一個復(fù)雜頁面的時候也可以拆分成一個個具有簡單功能的組件,然后再組合成你滿足各種需求的頁面。
其實我們函數(shù)式編程里面的組合也是類似,函數(shù)組合就是一種將已被分解的簡單任務(wù)組織成復(fù)雜的整體過程。
現(xiàn)在我們有這樣一個需求:給你一個字符串,將這個字符串轉(zhuǎn)化成大寫,然后逆序。
你可能會這么寫。
// 例 1.1 var str = "function program" // 一行代碼搞定 function oneLine(str) { var res = str.toUpperCase().split("").reverse().join("") return res; } // 或者 按要求一步一步來,先轉(zhuǎn)成大寫,然后逆序 function multiLine(str) { var upperStr = str.toUpperCase() var res = upperStr.split("").reverse().join("") return res; } console.log(oneLine(str)) // MARGORP NOITCNUF console.log(multiLine(str)) // MARGORP NOITCNUF
可能看到這里你并沒有覺得有什么不對的,但是現(xiàn)在產(chǎn)品又突發(fā)奇想,改了下需求,把字符串大寫之后,把每個字符拆開之后組裝成一個數(shù)組,比如 ’aaa‘ 最終會變成 [A, A, A]。
那么這個時候我們就需要更改我們之前我們封裝的函數(shù)。這就修改了以前封裝的代碼,其實在設(shè)計模式里面就是破壞了開閉原則。
那么我們?nèi)绻炎铋_始的需求代碼寫成這個樣子,以函數(shù)式編程的方式來寫。
// 例 1.2 var str = "function program" function stringToUpper(str) { return str.toUpperCase() } function stringReverse(str) { return str.split("").reverse().join("") } var toUpperAndReverse = 組合(stringReverse, stringToUpper) var res = toUpperAndReverse(str)
那么當我們需求變化的時候,我們根本不需要修改之前封裝過的東西。
// 例 2 var str = "function program" function stringToUpper(str) { return str.toUpperCase() } function stringReverse(str) { return str.split("").reverse().join("") } // var toUpperAndReverse = 組合(stringReverse, stringToUpper) // var res = toUpperAndReverse(str) function stringToArray(str) { return str.split("") } var toUpperAndArray = 組合(stringReverse, stringToUpper) toUpperAndArray(str)
可以看到當變更需求的時候,我們沒有打破以前封裝的代碼,只是新增了函數(shù)功能,然后把函數(shù)進行重新組合。
這里可能會有人說,需求修改,肯定要更改代碼呀,你這不是也刪除了以前的代碼么,也不是算破壞了開閉原則么。我這里聲明一下,開閉原則是指一個軟件實體如類、模塊和函數(shù)應(yīng)該對擴展開放,對修改關(guān)閉。是針對我們封裝,抽象出來的代碼,而是調(diào)用邏輯。所以這樣寫并不算破壞開閉原則。
突然產(chǎn)品又靈光一閃,又想改一下需求,把字符串大寫之后,再翻轉(zhuǎn),再轉(zhuǎn)成數(shù)組。
要是你按照以前的思考,沒有進行抽象,你肯定心理一萬只草泥馬在奔騰,但是如果你抽象了,你完全可以不慌。
// 例 3 var str = "function program" function stringToUpper(str) { return str.toUpperCase() } function stringReverse(str) { return str.split("").reverse().join("") } function stringToArray(str) { return str.split("") } var strUpperAndReverseAndArray = 組合(stringToArray, stringReverse, stringToUpper) strUpperAndReverseAndArray(str)
發(fā)現(xiàn)并沒有更換你之前封裝的代碼,只是更換了函數(shù)的組合方式??梢钥吹?,組合的方式是真的就是抽象單一功能的函數(shù),然后再組成復(fù)雜功能。這種方式既鍛煉了你的抽象能力,也給維護帶來巨大的方便。
但是上面的組合我只是用漢字來代替的,我們應(yīng)該如何去實現(xiàn)這個組合呢。首先我們可以知道,這是一個函數(shù),同時參數(shù)也是函數(shù),返回值也是函數(shù)。
我們看到例 2, 怎么將兩個函數(shù)進行組合呢,根據(jù)上面說的,參數(shù)和返回值都是函數(shù),那么我們可以確定函數(shù)的基本結(jié)構(gòu)如下(順便把組合換成英文的 compose)。
function twoFuntionCompose(fn1, fn2) { return function() { // code } }
我們再思考一下,如果我們不用 compose 這個函數(shù),在例 2 中怎么將兩個函數(shù)合成呢,我們是不是也可以這么做來達到組合的目的。
var res = stringReverse(stringToUpper(str))
那么按照這個邏輯是不是我們就可以寫出 twoFuntonCompose 的實現(xiàn)了,就是
function twoFuntonCompose(fn1, fn2) { return function(arg) { return fn1(fn2(arg)) } }
同理我們也可以寫出三個函數(shù)的組合函數(shù),四個函數(shù)的組合函數(shù),無非就是一直嵌套多層嘛,變成:
function multiFuntionCompose(fn1, fn2, .., fnn) { return function(arg) { return fnn(...(fn1(fn2(arg)))) } }
這種惡心的方式很顯然不是我們程序員應(yīng)該做的,然后我們也可以看到一些規(guī)律,無非就是把前一個函數(shù)的返回值作為后一個返回值的參數(shù),當直接到最后一個函數(shù)的時候,就返回。
所以按照正常的思維就會這么寫。
function aCompose(...args) { let length = args.length let count = length - 1 let result return function f1 (...arg1) { result = args[count].apply(this, arg1) if (count <= 0) { count = length - 1 return result } count-- return f1.call(null, result) } }
這樣寫沒問題,underscore 也是這么寫的,不過里面還有很多健壯性的處理,核心大概就是這樣。
但是作為一個函數(shù)式愛好者,盡量還是以函數(shù)式的方式去思考,所以就用 reduceRight 寫出如下代碼。
function compose(...args) { return (result) => { return args.reduceRight((result, fn) => { return fn(result) }, result) } }
當然對于 compose 的實現(xiàn)還有很多種方式,在這篇實現(xiàn) compose 的五種思路中還給出了另外腦洞大開的實現(xiàn)方式,在我看這篇文章之前,另外三種我是沒想到的,不過感覺也不是太有用,但是可以擴展我們的思路,有興趣的同學(xué)可以看一看。
注意:要傳給 compose 函數(shù)是有規(guī)范的,首先函數(shù)的執(zhí)行是從最后一個參數(shù)開始執(zhí)行,一直執(zhí)行到第一個,而且對于傳給 compose 作為參數(shù)的函數(shù)也是有要求的,必須只有一個形參,而且函數(shù)的返回值是下一個函數(shù)的實參。
對于 compose 從最后一個函數(shù)開始求值的方式如果你不是很適應(yīng)的話,你可以通過 pipe 函數(shù)來從左到右的方式。
function pipe(...args) { return (result) => { return args.reduce((result, fn) => { return fn(result) }, result) } }
實現(xiàn)跟 compose 差不多,只是把參數(shù)的遍歷方式從右到左(reduceRight)改為從左到右(reduce)。
之前是不是看過很多文章寫過如何實現(xiàn) compose,或者柯里化,部分應(yīng)用等函數(shù),但是你可能不知道是用來干啥的,也沒用過,所以記了又忘,忘了又記,看了這篇文章之后我希望這些你都可以輕松實現(xiàn)。后面會繼續(xù)講到柯里化和部分應(yīng)用的實現(xiàn)。
point-free在函數(shù)式編程的世界中,有這樣一種很流行的編程風格。這種風格被稱為 tacit programming,也被稱作為 point-free,point 表示的就是形參,意思大概就是沒有形參的編程風格。
// 這就是有參的,因為 word 這個形參 var snakeCase = word => word.toLowerCase().replace(/s+/ig, "_"); // 這是 pointfree,沒有任何形參 var snakeCase = compose(replace(/s+/ig, "_"), toLowerCase);
有參的函數(shù)的目的是得到一個數(shù)據(jù),而 pointfree 的函數(shù)的目的是得到另一個函數(shù)。
那這 pointfree 有什么用? 它可以讓我們把注意力集中在函數(shù)上,參數(shù)命名的麻煩肯定是省了,代碼也更簡潔優(yōu)雅。 需要注意的是,一個 pointfree 的函數(shù)可能是由眾多非 pointfree 的函數(shù)組成的,也就是說底層的基礎(chǔ)函數(shù)大都是有參的,pointfree 體現(xiàn)在用基礎(chǔ)函數(shù)組合而成的高級函數(shù)上,這些高級函數(shù)往往可以作為我們的業(yè)務(wù)函數(shù),通過組合不同的基礎(chǔ)函數(shù)構(gòu)成我們的復(fù)制的業(yè)務(wù)邏輯。
可以說 pointfree 使我們的編程看起來更美,更具有聲明式,這種風格算是函數(shù)式編程里面的一種追求,一種標準,我們可以盡量的寫成 pointfree,但是不要過度的使用,任何模式的過度使用都是不對的。
另外可以看到通過 compose 組合而成的基礎(chǔ)函數(shù)都是只有一個參數(shù)的,但是往往我們的基礎(chǔ)函數(shù)參數(shù)很可能不止一個,這個時候就會用到一個神奇的函數(shù)(柯里化函數(shù))。
柯里化在維基百科里面是這么定義柯里化的:
在計算機科學(xué),柯里化(英語:Currying),又譯為卡瑞化或加里化,是把接受多個參數(shù)的函數(shù)變換成接受一個單一參數(shù)(最初函數(shù)的第一個參數(shù))的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。
在定義中獲取兩個比較重要的信息:
接受一個單一參數(shù)
返回結(jié)果是函數(shù)
這兩個要點不是 compose 函數(shù)參數(shù)的要求么,而且可以將多個參數(shù)的函數(shù)轉(zhuǎn)換成接受單一參數(shù)的函數(shù),豈不是可以解決我們再上面提到的基礎(chǔ)函數(shù)如果是多個參數(shù)不能用的問題,所以這就很清楚了柯里化函數(shù)的作用了。
柯里化函數(shù)可以使我們更好的去追求 pointfree,讓我們代碼寫得更優(yōu)美!
接下來我們具體看一個例子來理解柯里化吧:
比如你有一間士多店并且你想給你優(yōu)惠的顧客給個 10% 的折扣(即打九折):
function discount(price, discount) { return price * discount }
當一位優(yōu)惠的顧客買了一間價值$500的物品,你給他打折:
const price = discount(500, 0.10); // $50
你可以預(yù)見,從長遠來看,我們會發(fā)現(xiàn)自己每天都在計算 10% 的折扣:
const price = discount(1500,0.10); // $150 const price = discount(2000,0.10); // $200 // ... 等等很多
我們可以將 discount 函數(shù)柯里化,這樣我們就不用總是每次增加這 0.01 的折扣。
// 這個就是一個柯里化函數(shù),將本來兩個參數(shù)的 discount ,轉(zhuǎn)化為每次接收單個參數(shù)完成求職 function discountCurry(discount) { return (price) => { return price * discount; } } const tenPercentDiscount = discountCurry(0.1);
現(xiàn)在,我們可以只計算你的顧客買的物品都價格了:
tenPercentDiscount(500); // $50
同樣地,有些優(yōu)惠顧客比一些優(yōu)惠顧客更重要-讓我們稱之為超級客戶。并且我們想給這些超級客戶提供20%的折扣。
可以使用我們的柯里化的discount函數(shù):
const twentyPercentDiscount = discountCurry(0.2);
我們通過這個柯里化的 discount 函數(shù)折扣調(diào)為 0.2(即20%),給我們的超級客戶配置了一個新的函數(shù)。
返回的函數(shù) twentyPercentDiscount 將用于計算我們的超級客戶的折扣:
twentyPercentDiscount(500); // 100
我相信通過上面的 discountCurry 你已經(jīng)對柯里化有點感覺了,這篇文章是談的柯里化在函數(shù)式編程里面的應(yīng)用,所以我們再來看看在函數(shù)式里面怎么應(yīng)用。
現(xiàn)在我們有這么一個需求:給定的一個字符串,先翻轉(zhuǎn),然后轉(zhuǎn)大寫,找是否有TAOWENG,如果有那么就輸出 yes,否則就輸出 no。
function stringToUpper(str) { return str.toUpperCase() } function stringReverse(str) { return str.split("").reverse().join("") } function find(str, targetStr) { return str.includes(targetStr) } function judge(is) { console.log(is ? "yes" : "no") }
我們很容易就寫出了這四個函數(shù),前面兩個是上面就已經(jīng)寫過的,然后 find 函數(shù)也很簡單,現(xiàn)在我們想通過 compose 的方式來實現(xiàn) pointfree,但是我們的 find 函數(shù)要接受兩個參數(shù),不符合 compose 參數(shù)的規(guī)定,這個時候我們像前面一個例子一樣,把 find 函數(shù)柯里化一下,然后再進行組合:
// 柯里化 find 函數(shù) function findCurry(targetStr) { return str => str.includes(targetStr) } const findTaoweng = findCurry("TAOWENG") const result = compose(judge, findTaoweng, stringReverse, stringToUpper)
看到這里是不是可以看到柯里化在達到 pointfree 是非常的有用,較少參數(shù),一步一步的實現(xiàn)我們的組合。
但是通過上面那種方式柯里化需要去修改以前封裝好的函數(shù),這也是破壞了開閉原則,而且對于一些基礎(chǔ)函數(shù)去把源碼修改了,其他地方用了可能就會有問題,所以我們應(yīng)該寫一個函數(shù)來手動柯里化。
根據(jù)定義之前對柯里化的定義,以及前面兩個柯里化函數(shù),我們可以寫一個二元(參數(shù)個數(shù)為 2)的通用柯里化函數(shù):
function twoCurry(fn) { return function(firstArg) { // 第一次調(diào)用獲得第一個參數(shù) return function(secondArg) { // 第二次調(diào)用獲得第二個參數(shù) return fn(firstArg, secondArg) // 將兩個參數(shù)應(yīng)用到函數(shù) fn 上 } } }
所以上面的 findCurry 就可以通過 twoCurry 來得到:
const findCurry = twoCurry(find)
這樣我們就可以不更改封裝好的函數(shù),也可以使用柯里化,然后進行函數(shù)組合。不過我們這里只實現(xiàn)了二元函數(shù)的柯里化,要是三元,四元是不是我們又要要寫三元柯里化函數(shù),四元柯里化函數(shù)呢,其實我們可以寫一個通用的 n 元柯里化。
function currying(fn, ...args) { if (args.length >= fn.length) { return fn(...args) } return function (...args2) { return currying(fn, ...args, ...args2) } }
我這里采用的是遞歸的思路,當獲取的參數(shù)個數(shù)大于或者等于 fn 的參數(shù)個數(shù)的時候,就證明參數(shù)已經(jīng)獲取完畢,所以直接執(zhí)行 fn 了,如果沒有獲取完,就繼續(xù)遞歸獲取參數(shù)。
可以看到其實一個通用的柯里化函數(shù)核心思想是非常的簡單,代碼也非常簡潔,而且還支持在一次調(diào)用的時候可以傳多個參數(shù)(但是這種傳遞多個參數(shù)跟柯里化的定義不是很合,所以可以作為一種柯里化的變種)。
我這里重點不是講柯里化的實現(xiàn),所以沒有寫得很健壯,更強大的柯里化函數(shù)可見羽訝的:JavaScript專題之函數(shù)柯里化。部分應(yīng)用
部分應(yīng)用是一種通過將函數(shù)的不可變參數(shù)子集,初始化為固定值來創(chuàng)建更小元數(shù)函數(shù)的操作。簡單來說,如果存在一個具有五個參數(shù)的函數(shù),給出三個參數(shù)后,就會得到一個、兩個參數(shù)的函數(shù)。
看到上面的定義可能你會覺得這跟柯里化很相似,都是用來縮短函數(shù)參數(shù)的長度,所以如果理解了柯里化,理解部分應(yīng)用是非常的簡單:
function debug(type, firstArg, secondArg) { if(type === "log") { console.log(firstArg, secondArg) } else if(type === "info") { console.info(firstArg, secondArg) } else if(type === "warn") { console.warn(firstArg, secondArg) } else { console.error(firstArg, secondArg) } } const logDebug = 部分應(yīng)用(debug, "log") const infoDebug = 部分應(yīng)用(debug, "info") const warnDebug = 部分應(yīng)用(debug, "warn") const errDebug = 部分應(yīng)用(debug, "error") logDebug("log:", "測試部分應(yīng)用") infoDebug("info:", "測試部分應(yīng)用") warnDebug("warn:", "測試部分應(yīng)用") errDebug("error:", "測試部分應(yīng)用")
debug方法封裝了我們平時用 console 對象調(diào)試的時候各種方法,本來是要傳三個參數(shù),我們通過部分應(yīng)用的封裝之后,我們只需要根據(jù)需要調(diào)用不同的方法,傳必須的參數(shù)就可以了。
我這個例子可能你會覺得沒必要這么封裝,根本沒有減少什么工作量,但是如果我們在 debug 的時候不僅是要打印到控制臺,還要把調(diào)試信息保存到數(shù)據(jù)庫,或者做點其他的,那是不是這個封裝就有用了。
因為部分應(yīng)用也可以減少參數(shù),所以他在我們進行編寫組合函數(shù)的時候也占有一席之地,而且可以更快傳遞需要的參數(shù),留下為了 compose 傳遞的參數(shù),這里是跟柯里化比較,因為柯里化按照定義的話,一次函數(shù)調(diào)用只能傳一個參數(shù),如果有四五個參數(shù)就需要:
function add(a, b, c, d) { return a + b + c +d } // 使用柯里化方式來使 add 轉(zhuǎn)化為一個一元函數(shù) let addPreThreeCurry = currying(add)(1)(2)(3) addPreThree(4) // 10
這種連續(xù)調(diào)用(這里所說的柯里化是按照定義的柯里化,而不是我們寫的柯里化變種),但是用部分應(yīng)用就可以:
// 使用部分應(yīng)用的方式使 add 轉(zhuǎn)化為一個一元函數(shù) const addPreThreePartial = 部分應(yīng)用(add, 1, 2, 3) addPreThree(4) // 10
既然我們現(xiàn)在已經(jīng)明白了部分應(yīng)用這個函數(shù)的作用了,那么還是來實現(xiàn)一個吧,真的是非常的簡單:
// 通用的部分應(yīng)用函數(shù)的核心實現(xiàn) function partial(fn, ...args) { return (..._arg) => { return fn(...args, ..._arg); } }
另外不知道你有沒有發(fā)現(xiàn),這個部分應(yīng)用跟 JavaScript 里面的 bind 函數(shù)很相似,都是把第一次穿進去的參數(shù)通過閉包存在函數(shù)里,等到再次調(diào)用的時候再把另外的參數(shù)傳給函數(shù),只是部分應(yīng)用不用指定 this,所以也可以用 bind 來實現(xiàn)一個部分應(yīng)用函數(shù)。
// 通用的部分應(yīng)用函數(shù)的核心實現(xiàn) function partial(fn, ...args) { return fn.bind(null, ...args) }
另外可以看到實際上柯里化和部分應(yīng)用確實很相似,所以這兩種技術(shù)很容易被混淆。它們主要的區(qū)別在于參數(shù)傳遞的內(nèi)部機制與控制:
柯里化在每次分布調(diào)用時都會生成嵌套的一元函數(shù)。在底層 ,函數(shù)的最終結(jié)果是由這些一元函數(shù)逐步組合產(chǎn)生的。同時,curry 的變體允許同時傳遞一部分參數(shù)。因此,可以完全控制函數(shù)求值的時間與方式。
部分應(yīng)用將函數(shù)的參數(shù)與一些預(yù)設(shè)值綁定(賦值),從而產(chǎn)生一個擁有更少參數(shù)的新函數(shù)。改函數(shù)的閉包中包含了這些已賦值的參數(shù),在之后的調(diào)用中被完全求值。
總結(jié)在這篇文章里我重點想介紹的是函數(shù)以組合的方式來完成我們的需求,另外介紹了一種函數(shù)式編程風格:pointfree,讓我們在函數(shù)式編程里面有了一個最佳實踐,盡量寫成 pointfree 形式(盡量,不是都要),然后介紹了通過柯里化或者部分應(yīng)用來減少函數(shù)參數(shù),符合 compose 或者 pipe 的參數(shù)要求。
所以這種文章的重點是理解我們?nèi)绾稳ソM合函數(shù),如何去抽象復(fù)雜的函數(shù)為顆粒度更小,功能單一的函數(shù)。這將使我們的代碼更容易維護,更具聲明式的特點。
對于這篇文章里面提到的其他概念:閉包、作用域,然后柯里化的其他用途我希望是在番外篇里面更深入的去理解,而這篇文章主要掌握函數(shù)組合就行了。參考文章
JavaScript函數(shù)式編程之pointfree與聲明式編程
Understanding Currying in JavaScript
《JavaScript 函數(shù)式編程指南》
文章首發(fā)于自己的個人網(wǎng)站桃園,另外也可以在 github blog 上找到。
如果有興趣,也可以關(guān)注我的個人公眾號:「前端桃園」
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/101953.html
摘要:簡單來說高階組件就是一個函數(shù),它接受一個組件作為參數(shù)然后返回一個新組件。主要用于組件之間邏輯復(fù)用。使用由于數(shù)據(jù)請求是異步的,為了不讓用戶看到一片空白,當數(shù)據(jù)請求還沒有返回時,展示組件。組合函數(shù),提升代碼可閱讀性。 簡單來說高階組件(HOC)就是一個函數(shù),它接受一個組件作為參數(shù)然后返回一個新組件。HOC 主要用于組件之間邏輯復(fù)用。比如你寫了幾個組件,他們之間的邏輯幾乎相同,就可以用 HOC 對...
摘要:今天這篇文章主要介紹函數(shù)式編程的思想。函數(shù)式編程通過最小化變化使得代碼更易理解。在函數(shù)式編程里面,組合是一個非常非常非常重要的思想。可以看到函數(shù)式編程在開發(fā)中具有聲明模式。而函數(shù)式編程旨在盡可能的提高代碼的無狀態(tài)性和不變性。 最開始接觸函數(shù)式編程的時候是在小米工作的時候,那個時候看老大以前寫的代碼各種 compose,然后一些 ramda 的一些工具函數(shù),看著很吃力,然后極力吐槽函數(shù)式...
摘要:在函數(shù)式編程的組合中,我們是從右到左執(zhí)行的,上述的例子中我們借助函數(shù)實現(xiàn)組合,當然,我們也可以用自己的方式實現(xiàn)。小結(jié)函數(shù)式編程隨著多核的發(fā)展,開始再次出現(xiàn)在我們的視野中,有時候也會擔心過于吹捧函數(shù)式,反而落入俗套。 程序的本質(zhì)是什么?數(shù)據(jù)結(jié)構(gòu)+算法?。。∥蚁脒@也是很多程序員給出的答案,我自己也認可這一觀點,當我們了解了某一門編程語之后,接下來我們面對的往往是數(shù)據(jù)結(jié)構(gòu)和算法的學(xué)習(xí)。而現(xiàn)在...
摘要:函數(shù)式編程逐漸被邊緣化,被拋棄到學(xué)術(shù)界和非主流的場外。組合式編程的重新崛起年左右,有個巨大的變化爆發(fā)了。人們開始逐漸在私下里談?wù)摵瘮?shù)式編程。箭頭函數(shù)對于函數(shù)式編程的爆發(fā)起到了推動劑的作用。現(xiàn)在很少看到那種不用函數(shù)式編程的大型應(yīng)用了。 showImg(https://segmentfault.com/img/remote/1460000009036867?w=800&h=364); 本...
摘要:函數(shù)式編程,一看這個詞,簡直就是學(xué)院派的典范。所以這期周刊,我們就重點引入的函數(shù)式編程,淺入淺出,一窺函數(shù)式編程的思想,可能讓你對編程語言的理解更加融會貫通一些。但從根本上來說,函數(shù)式編程就是關(guān)于如使用通用的可復(fù)用函數(shù)進行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數(shù)式編程(Functional Programming),一...
閱讀 1035·2021-11-23 10:11
閱讀 3875·2021-11-16 11:50
閱讀 942·2021-10-14 09:43
閱讀 2727·2021-10-14 09:42
閱讀 2724·2021-09-22 16:02
閱讀 1072·2019-08-29 10:57
閱讀 3389·2019-08-29 10:57
閱讀 2285·2019-08-26 13:52