自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一文看懂:函數(shù)式編程為何這么火?

開發(fā) 前端
函數(shù)式編程的無狀態(tài)和不可變性使得它在并發(fā)編程中非常有用。它可以幫助避免并發(fā)時(shí)常見的問題,如競(jìng)態(tài)條件和死鎖。


近幾年函數(shù)式編程變得越來越流行,很多開發(fā)語言中都增加了很多函數(shù)式編程的能力。

比如在JavaScript中使用map函數(shù)將數(shù)組中的每個(gè)元素乘以2:

const numbers = [1, 2, 3, 4, 5, 6];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // 輸出: [2, 4, 6, 8, 10, 12]

可以看到,這樣編寫的代碼更緊湊、可讀性更強(qiáng)。

當(dāng)然函數(shù)式編程還有很多好處,本文就帶大家來探索下函數(shù)式編程的概念和實(shí)際應(yīng)用。

1. 什么是函數(shù)式編程?

1.1 概念介紹

函數(shù)式編程(Functional Programming,簡(jiǎn)稱FP)是一種編程范式,就像你在拼圖游戲中只能用特定的塊來構(gòu)建畫面,F(xiàn)P要求我們用函數(shù)來構(gòu)建程序的邏輯。這種范式強(qiáng)調(diào)將計(jì)算過程分解為可復(fù)用函數(shù)的集合。

函數(shù)式編程的理論基礎(chǔ)是λ演算(lambda),由數(shù)學(xué)家阿隆佐·邱奇在20世紀(jì)30年代引入,這是一套用于研究函數(shù)如何定義、如何計(jì)算以及如何遞歸的數(shù)學(xué)系統(tǒng)。想象一下,λ演算就像是樂高積木的基礎(chǔ)板,在這個(gè)基礎(chǔ)板上,你可以構(gòu)建任何形式的數(shù)據(jù)結(jié)構(gòu)和函數(shù),就像你可以用樂高積木構(gòu)建任何形狀的模型一樣。

圖片圖片

在函數(shù)式編程中,函數(shù)定義了輸入數(shù)據(jù)與輸出數(shù)據(jù)之間的關(guān)系。這可以用我們的初中數(shù)學(xué)知識(shí)來理解:y=f(x) ,它就是函數(shù)的最一般定義。

函數(shù)式編程可以用廚房烹飪來比喻。烹飪中,每道菜的制作都需要一系列步驟,而這些步驟可以被視為一連串的函數(shù)。每個(gè)函數(shù)都是一個(gè)烹飪動(dòng)作,比如切菜、炒菜、煮菜。它們接收原料(輸入數(shù)據(jù)),然后通過一系列處理(函數(shù)操作),最終出品一道菜(輸出結(jié)果)。

1.2 函數(shù)式編程的精髓

函數(shù)式編程的核心理念是描述“做什么”(what to do),而不是“怎么做”(how to do it)。這提供了一個(gè)更高的抽象層次,讓問題描述得更清晰。

舉個(gè)例子,給你一個(gè)裝有蘋果的籃子,如果我說“挑出所有紅蘋果”,這就是描述“做什么”,而不是告訴你具體的挑選步驟。

再舉個(gè)代碼的例子,計(jì)算列表中所有數(shù)字的和,使用Haskell編寫:

sumNumbers = sum [1, 2, 3, 4, 5]

這里,sum是一個(gè)函數(shù),它知道如何取一個(gè)數(shù)字列表并計(jì)算它們的和。你不需要告訴它如何去做這件事情(如初始化累加器,循環(huán)等等),你只需要告訴它你想要做的事情(計(jì)算這個(gè)列表的和)。

2. 函數(shù)式編程的特點(diǎn)2.1 Stateless:無狀態(tài)函數(shù)

函數(shù)式編程中的函數(shù)不保留任何狀態(tài),函數(shù)沒有副作用,它們只是接受輸入并返回輸出,而不改變?nèi)魏瓮獠繝顟B(tài)。

就像一個(gè)好的咖啡機(jī),每次用相同的咖啡豆都能得到一杯品質(zhì)一致的咖啡。

這種無狀態(tài)的特性使得函數(shù)式編程成為一種非常適合進(jìn)行并行計(jì)算和分布式計(jì)算的編程范式。

2.2 Immutable:不可變數(shù)據(jù)

在函數(shù)式編程中,輸入的數(shù)據(jù)是不可變的。這意味著函數(shù)不會(huì)改變輸入的數(shù)據(jù),而是生成新的數(shù)據(jù)集作為輸出。

這就像在寫字時(shí)用鉛筆和橡皮擦,函數(shù)式編程只允許你用鉛筆寫在新的紙上,而不是在原來的紙上擦掉重寫。

3.函數(shù)式編程的優(yōu)勢(shì)和劣勢(shì)

3.1 優(yōu)勢(shì)

代碼簡(jiǎn)潔

函數(shù)式編程大量使用函數(shù),減少了代碼的重復(fù),因此程序比較短。

并行執(zhí)行

由于函數(shù)不保持狀態(tài),它們可以安全地并行執(zhí)行,就像多個(gè)人同時(shí)解不同的拼圖一樣,彼此之間不會(huì)產(chǎn)生干擾。

無執(zhí)行順序問題

函數(shù)的執(zhí)行不依賴于程序的狀態(tài),因此不需要擔(dān)心執(zhí)行順序的問題。

代碼重用性

函數(shù)式編程鼓勵(lì)代碼的重用,復(fù)制粘貼函數(shù)不會(huì)引起副作用,就像使用模塊化的積木一樣,可以在不同的作品中重復(fù)使用。

延遲執(zhí)行

函數(shù)式編程允許延遲執(zhí)行,只有在真正需要結(jié)果時(shí),才會(huì)計(jì)算函數(shù)的值。

確定性

給定相同的輸入,函數(shù)總是產(chǎn)生相同的輸出,這提供了程序的可預(yù)測(cè)性。

3.2 劣勢(shì)

內(nèi)存占用大

由于不改變?cè)紨?shù)據(jù),可能會(huì)導(dǎo)致數(shù)據(jù)被頻繁地復(fù)制,這會(huì)增加內(nèi)存的使用,還可能需要更多次的讀取和寫入操作。

學(xué)習(xí)曲線陡峭

對(duì)于習(xí)慣了命令式編程的開發(fā)者來說,函數(shù)式編程的概念可能需要時(shí)間來適應(yīng)。概念如純函數(shù)、不可變性、遞歸、高階函數(shù)等可能初學(xué)者難以理解。

4. 函數(shù)式編程相關(guān)技術(shù)4.1 First-class function: 頭等函數(shù)

在函數(shù)式編程中,函數(shù)可以作為參數(shù)傳遞,可以作為返回值,也可以賦給變量。這就像在一個(gè)游樂園里,所有游樂設(shè)施都是“一等公民”,你可以隨意搭配使用。

4.2 Tail recursion optimization: 尾遞歸優(yōu)化

尾遞歸是一種特殊的遞歸形式,它允許編譯器優(yōu)化遞歸調(diào)用,避免占用過多的??臻g,使得遞歸的效率接近循環(huán)。

4.3 Map & Reduce: 映射與歸約

Map和Reduce是處理集合的兩個(gè)強(qiáng)大工具,它們讓代碼更加簡(jiǎn)潔和易讀。Map用于轉(zhuǎn)換數(shù)據(jù),Reduce用于合并數(shù)據(jù)。

4.4 Pipeline: 管道

管道是一種將多個(gè)函數(shù)組合起來的方法,數(shù)據(jù)通過管道流過,依次被這些函數(shù)處理。下面是一個(gè)管道的例子,在這個(gè)例子中,我們首先將number變量值翻倍(double),然后將結(jié)果增加1(increment),最后對(duì)結(jié)果進(jìn)行平方(square)。

from functools import reduce

# 定義一系列純函數(shù)
def double(x):
    return x * 2

def increment(x):
    return x + 1

def square(x):
    return x * x

# 創(chuàng)建一個(gè)函數(shù)列表,表示要應(yīng)用的操作順序
functions = [double, increment, square]

# 初始值
number = 3

# 使用reduce創(chuàng)建一個(gè)管道,將函數(shù)應(yīng)用于初始值
result = reduce(lambda acc, func: func(acc), functions, number)

print(result)  # 輸出

4.5 Recursing: 遞歸

遞歸是一種強(qiáng)大的編程技術(shù),它讓我們可以用簡(jiǎn)潔的方式描述復(fù)雜的問題,正符合函數(shù)式編程的精髓。

4.6 Currying: 柯里化

柯里化是將接受多個(gè)參數(shù)的函數(shù)轉(zhuǎn)換成一系列使用一個(gè)參數(shù)的函數(shù)的技術(shù)??吕锘梢允勾a更加模塊化,每個(gè)函數(shù)的功能更加單一,這有助于提高代碼的可讀性和可維護(hù)性。同時(shí),柯里化也可以使代碼更加靈活,因?yàn)槲覀兛梢酝ㄟ^組合不同的函數(shù)來實(shí)現(xiàn)不同的功能。舉個(gè)例子:

def add(a, b):
    return a + b

def curry_add(a):
    def add_b(b):
        return add(a, b)
    return add_b

# 使用柯里化的add函數(shù)
add_5 = curry_add(5)  # 創(chuàng)建一個(gè)新的函數(shù),這個(gè)函數(shù)會(huì)將其參數(shù)加5
print(add_5(10))  # 輸出: 15

當(dāng)我們調(diào)用curry_add(5)時(shí),我們得到了一個(gè)新的函數(shù)add_5,它固定了第一個(gè)參數(shù)為5,并等待第二個(gè)參數(shù)。當(dāng)我們隨后調(diào)用add_5(10)時(shí),它實(shí)際上調(diào)用的是add(5, 10)。

4.7 Higher-order function: 高階函數(shù)

高階函數(shù)可以接受其他函數(shù)作為參數(shù)或者將函數(shù)作為返回值。這類似于你有一個(gè)能裝其他小盒子的大盒子,這個(gè)大盒子可以用來組織和管理那些小盒子。

舉個(gè)Python中的例子,reduce就是一個(gè)高階函數(shù),在這里它的第一個(gè)參數(shù)是匿名函數(shù)。

from functools import reduce  
  
def sum_numbers(numbers):  
    return reduce(lambda x, y: x + y, numbers, 0)

5. 函數(shù)式編程語言

很多語言都提供了函數(shù)式編程的支持,不過支持的程度不太一樣,這里做個(gè)簡(jiǎn)單的總結(jié)。

Haskell: 完全純函數(shù)式編程語言

Haskell是一個(gè)標(biāo)準(zhǔn)的純函數(shù)式編程語言,所有的操作都是通過函數(shù)來完成的,就像在一個(gè)世界里,所有的建筑都是用同一種類型的積木搭建的。

F#, Ocaml, Clojure, Scala: 容易寫純函數(shù)的語言

這些語言設(shè)計(jì)時(shí)考慮到了函數(shù)式編程的特性,使得編寫純函數(shù)變得容易。

C#, Java, JavaScript: 需要花點(diǎn)精力寫純函數(shù)的語言

雖然這些語言不是純函數(shù)式編程語言,但它們提供了支持函數(shù)式編程的特性,只是需要程序員更加注意避免副作用。

大部分語言都支持的函數(shù)式編程三套件:Map、Reduce、Filter

這三個(gè)函數(shù)是函數(shù)式編程中處理數(shù)據(jù)集合的基本工具,就像在廚房里的刀、叉、勺是處理食物的基礎(chǔ)一樣。

6. 裝飾器模式

這里之所以提到裝飾器模式,是因?yàn)樗秃瘮?shù)式編程有很多共同點(diǎn)。函數(shù)式編程和裝飾器模式都關(guān)注于函數(shù)的靈活性、可復(fù)用性和不修改現(xiàn)有代碼的原則。

裝飾器模式可以向現(xiàn)有功能添加新功能,而不改變其結(jié)構(gòu)。這就像給一個(gè)手機(jī)裝上手機(jī)殼,增加了新的功能(比如防摔),但手機(jī)本身并沒有改變。

圖片圖片

裝飾器的本質(zhì)就是函數(shù),它也遵循函數(shù)式編程的一些原則。下邊我們提供兩個(gè)例子。

6.1 Python中的裝飾器

在Python中,裝飾器模式通常使用裝飾器函數(shù)來實(shí)現(xiàn)。裝飾器函數(shù)是一個(gè)接受函數(shù)作為參數(shù),并返回一個(gè)新的函數(shù)的函數(shù)。通過裝飾器函數(shù),我們可以動(dòng)態(tài)地給一個(gè)函數(shù)添加一些新的功能,比如日志記錄、性能測(cè)試、事務(wù)處理等。

下面是一個(gè)簡(jiǎn)單的示例,演示了如何使用裝飾器函數(shù)來給一個(gè)函數(shù)添加日志記錄功能:

def log(func):  
    def wrapper(*args, **kwargs):  
        print("Calling function:", func.__name__)  
        result = func(*args, **kwargs)  
        print("Function returned:", result)  
        return result  
    return wrapper  
  
@log  
def add(x, y):  
    return x + y

當(dāng)我們使用@log注解add時(shí),我們實(shí)際上是將add傳遞給了log,并且使用log返回的wrapper函數(shù)來替代原始的add。

6.2 Golang的裝飾器

在Go語言中,裝飾器模式?jīng)]有語法糖像Python的裝飾器那樣直觀。在Go中,你需要手動(dòng)將一個(gè)函數(shù)傳遞給另一個(gè)函數(shù),從而實(shí)現(xiàn)裝飾。下面還是記錄日志的例子:

package main  

import "fmt"  

// 原始函數(shù)  
func add(x, y int) int {  
    return x + y  
}  

// 裝飾器函數(shù)  
func logDecorator(f func(int, int) int) func(int, int) int {  
    return func(x, y int) int {  
        fmt.Printf("Calling function: add\n")  
        result := f(x, y)  
        fmt.Printf("Function returned: %d\n", result)  
        return result  
    }  
}  

func main() {  
    // 使用裝飾器函數(shù)包裝原始函數(shù)  
    decoratedAdd := logDecorator(add)  

    // 調(diào)用裝飾后的函數(shù)  
    fmt.Println(decoratedAdd(2, 3))  
}

7. 函數(shù)式編程在實(shí)際中的應(yīng)用

大數(shù)據(jù)處理:在大數(shù)據(jù)領(lǐng)域,函數(shù)式編程的概念,特別是Map和Reduce,被廣泛應(yīng)用于數(shù)據(jù)的處理。想象一下,你有一座由許多小石頭組成的山,Map就是用來挑選出你需要的石頭,而Reduce則幫你把這些石頭粘合成一座小山丘。

響應(yīng)式編程:響應(yīng)式編程(Reactive Programming)是一種與函數(shù)式編程有著密切關(guān)系的編程范式,它側(cè)重于數(shù)據(jù)流和變化的傳播。這就像是一個(gè)復(fù)雜的多米諾骨牌裝置,當(dāng)你觸動(dòng)一個(gè)骨牌,整個(gè)裝置按照既定的路徑和順序倒下。

Web開發(fā):在Web開發(fā)中,函數(shù)式編程也有其用武之地。例如,React庫(kù)利用了函數(shù)式編程的概念來管理用戶界面的狀態(tài),使得狀態(tài)的變化可預(yù)測(cè)和可管理。

并發(fā)編程:函數(shù)式編程的無狀態(tài)和不可變性使得它在并發(fā)編程中非常有用。它可以幫助避免并發(fā)時(shí)常見的問題,如競(jìng)態(tài)條件和死鎖。

8. 如何學(xué)習(xí)函數(shù)式編程?

  1. 從基礎(chǔ)概念開始:理解函數(shù)式編程的關(guān)鍵是從其基本概念開始,比如純函數(shù)、不可變性和函數(shù)組合。就像學(xué)習(xí)任何新技能一樣,掌握基礎(chǔ)是成功的關(guān)鍵。
  2. 學(xué)習(xí)和實(shí)踐:學(xué)習(xí)函數(shù)式編程不僅僅是理論上的,更重要的是通過實(shí)踐來深化理解。嘗試用函數(shù)式編程解決實(shí)際問題,就像是通過游戲來學(xué)習(xí)游泳,理論知識(shí)和實(shí)際動(dòng)作的結(jié)合才能讓你游得更好。
  3. 使用函數(shù)式編程語言:嘗試使用像Haskell這樣的純函數(shù)式編程語言,或者在支持函數(shù)式編程的語言中使用函數(shù)式特性,比如JavaScript中的高階函數(shù)和數(shù)組方法。
  4. 參與社區(qū)和項(xiàng)目:加入函數(shù)式編程的社區(qū),參與開源項(xiàng)目,這可以幫助你更快地學(xué)習(xí)和應(yīng)用函數(shù)式編程的概念。

結(jié)語

函數(shù)式編程是一個(gè)非常強(qiáng)大且具有挑戰(zhàn)性的編程范式,它提供了一種不同的思考和解決問題的方式。雖然它可能看起來有點(diǎn)像是數(shù)學(xué)或者哲學(xué),但一旦你掌握了它,就會(huì)發(fā)現(xiàn)它能幫你寫出更清晰、更可維護(hù)、更可靠的代碼。


責(zé)任編輯:武曉燕 來源: 螢火架構(gòu)
相關(guān)推薦

2019-08-06 09:00:00

JavaScript函數(shù)式編程前端

2022-07-19 15:24:45

Python編程技術(shù)

2020-03-31 14:40:24

HashMap源碼Java

2022-07-15 08:16:56

Stream函數(shù)式編程

2016-08-18 00:21:12

網(wǎng)絡(luò)爬蟲抓取網(wǎng)絡(luò)

2024-08-12 12:30:27

2025-01-20 09:15:00

iOS 18.3蘋果iOS 18

2021-08-02 06:56:19

TypeScript編程語言編譯器

2019-07-01 09:22:15

Linux操作系統(tǒng)硬件

2019-05-22 09:50:42

Python沙箱逃逸網(wǎng)絡(luò)攻擊

2018-08-15 09:26:56

2024-07-18 08:00:00

2021-02-21 11:25:17

云計(jì)算IaaSPaaS

2021-05-11 10:40:29

JUCAQSJava

2021-05-12 15:16:17

JUCAQSJava

2024-10-10 17:55:57

LinuxACL訪問控制列表

2023-12-18 10:45:31

2019-02-13 15:38:09

存儲(chǔ)虛擬化云計(jì)算

2022-04-26 13:41:16

區(qū)塊鏈比特幣數(shù)據(jù)庫(kù)

2025-03-25 09:06:11

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)