亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

從歷史講起JavaScript基因里的函數(shù)式編程實例

 更新時間:2022年10月15日 09:19:59   作者:掘金安東尼  
這篇文章主要為大家介紹了從歷史講起JavaScript基因里的函數(shù)式編程實例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

本篇序言

本瓜很喜歡看歷史,讀史可知興替、使人明智,作為程序員看“技術的演替歷史”同樣如此。過程是越看越有味,仿佛先賢智慧的光照亮了我原本封閉的心,每每只能感嘆一個“服”字。所以,專欄第一篇打算先從技術歷史講起,從函數(shù)式編程的淵源講起。

看完本篇:

你會知道為什么有人會說 “計算機是數(shù)學家一次失敗思考的產(chǎn)物”;

你會知道為什么 “ lambda 演算定義函數(shù)有效計算” ;

你會知道編程概念中 “閉包最初是如何形成的”

你還會知道為什么標題要說 “JavaScript 基因里寫著函數(shù)式編程” ;

話不多說,開沖了~ ??‍??‍??‍

一、數(shù)學之美

函數(shù)式編程的歷史最早可以追溯到 1930 年,一個叫 丘奇(Church)的人,提出了 λ (lambda)演算,這是所有函數(shù)式編程語言的基礎。

那這人為啥要提出這個演算?1930 年這個時間比世界上第一臺計算機誕生的時間都還要早 16 年。提出這個肯定不是因為計算機編程。

沒錯,他是為了解決一個數(shù)學問題。

這個數(shù)學問題是:

著名的希爾伯特第十問題—— 判定問題 (1900 年提出)

我們不妨來“淺看”一下這個數(shù)學問題,可以說這個問題促使了計算機的形成。

什么是希爾伯特第十問題之判定問題?

本瓜嘗試用通俗的表達解釋一下:

很簡單,有下列這樣一個方程:

其中所有的數(shù)(aj、bj、c)都是整數(shù),求:能否找到一組 xj (全部為整數(shù))的解?

乍一看這個公式有點費解。。。

其實我們可以構建一個大家都熟悉的實例,保證一看就明白了~

我敲,這不就是勾股定理嗎?勾三股四弦五,老祖宗在西周時就發(fā)現(xiàn)了。

符合判定問題的實例方程還有很多,比如:裴蜀等式、佩爾方程、四平方和定理、以及著名的【費馬大猜想】等等。

噢!希爾伯特提出判定問題,旨在“一勞永逸”,如果這個問題被解決了,那么它的子問題也都能被同樣解決。所以,在 1900 年到 1930 年之間,以希爾伯特為代表的數(shù)學家們 試圖構建一個自動化定理證明的系統(tǒng),讓公理系統(tǒng)內(nèi)的所有命題都能用一套既定的規(guī)則得以證明或證偽。

說白了,就是這群數(shù)學家也想偷懶,證明各類數(shù)學公式已經(jīng)累了,想搞點自動化的通用流程,能夠用通用流程去證明或證偽數(shù)學難題。

大家都在前赴后繼的嘗試解決這個問題,直到 1930 年后,出現(xiàn)了 哥德爾、圖靈、丘奇 這些人,他們幾乎在同一時間,但又在不同角度對這個問題作出了解釋。

更為神奇的是,最終證明他們的結論竟然是等效的。

哥德爾不完備性定理中遞歸函數(shù) == 圖靈完備 == lambda 演算

他們徹底解決了希爾伯特第十問題嗎?

很遺憾,并沒有。

不過在這個過程中,他們搞清楚了一個很重要的問題,一個對計算機科學至關重要的元核心問題:

什么樣的函數(shù)是可以有效計算的?!

在這之前,數(shù)學家們對于這個問題并沒有一個普遍結論,只知道一些最簡單的函數(shù),以及通過簡單規(guī)則將簡單函數(shù)組合起來的函數(shù)(比如加法),是可以有效計算的。

這種感覺像是無心插柳,本來大家是沖著解決數(shù)學公式論證問題去的,最后不約而同的得出了“函數(shù)可有效計算”的定義。這個定義由此發(fā)展,成為了 21 世紀最具顛覆力量的學科 —— 計算機。

所以才有人說:計算機是數(shù)學家一次失敗思考的產(chǎn)物。

數(shù)學的局限也會造成計算機的局限。

不過依然無法掩蓋數(shù)學之美,美在它足夠基礎,但又隱藏著巨大的能量,影響著萬事萬物。

二、lambda 演算核心

各位,你有想過,什么樣的函數(shù)是可以有效計算的?

如果由你定義,你會從怎樣的角度去思考?

  • 由于本篇重點是講函數(shù)式編程起源的 lambda 演算,所以哥德爾和圖靈的解釋不作展開,在文尾有相關文章推薦,可自行了解。(尤其是圖靈機,一定多看看、體會體會)

丘奇給出了它的觀點:

有效計算的函數(shù)指的是:函數(shù)每一步都可被事先確定,而且該函數(shù)可在有限的步數(shù)之內(nèi)生成結果。

通俗來理解,“有效”即要在有限步驟內(nèi)產(chǎn)生確定的結果。

天才的丘奇給出了 lambda 演算表達式:

lambda x . body

其中 x 是輸入的參數(shù),body 是運算過程,意思是 x 經(jīng)過 body 的運算,然后返回結果。

lambda 演算的偉大之處在于它非常簡潔,揭示了計算的本質(zhì)。

細看 lambda 表達式,你會發(fā)現(xiàn)函數(shù)只能接受一個參數(shù),如果我們需要傳兩個參數(shù)呢?

其實也是能實現(xiàn)的,如下:

lambda x. ( lambda y. plus x y )

這就是沿用至今的函數(shù)式編程 柯里化 思想,傳入?yún)?shù) x,經(jīng)過運算體 body:lambda y. plus x y 的運算,body 又是一個 lambda 運算表達式,入?yún)⑹?y,新的運算體是 plus x y。

這種簡化的設計,讓我們無需過多的語法,便能實現(xiàn)接收多個參數(shù)。

lambda 演算核心還有兩條重要的規(guī)則:轉換 和 規(guī)約

  • 轉換

轉換的意思是:變量的名稱并不重要,比如以下兩種寫法是等效的,相當于變量名只是形參而已。

lambda x. ( lambda y. plus x y )
lambda y. ( lambda x. plus x y )
  • 規(guī)約

規(guī)約的意思是:我們可以對這個函數(shù)體中和對應函數(shù)標識符相關的部分做替換,替換方法是把標識符用參數(shù)值替換。

舉個例子:

(lambda x . x + 1) 3
// 規(guī)約后
3 + 1

這樣寫意味著 3 是形參 x 實際的值,數(shù)值“3”可直接取代引用的參數(shù)“x”,規(guī)約后即為 3 + 1

(lambda y . (lambda x . x + y)) q
// 規(guī)約后
lambda x . x + q

首先 q 是形參 y 實際的值,規(guī)約后,實際上就是求 lambda x . x + q

規(guī)約遠能做的很多變化,正是由于規(guī)約的存在,讓 lambda 演算可以實現(xiàn)遞歸,才讓它可以等效于圖靈完備。

我們再來概括一下:

  • lambda 核心表達式:lambda x . body,簡潔而優(yōu)雅;
  • 入?yún)⒅挥幸粋€,可以通過柯里化來實現(xiàn)接受多個參數(shù);
  • lambda 演算的“規(guī)約”規(guī)則是它實現(xiàn)復雜運算的重要機制,由繁化簡;
  • 多問一句:把函數(shù)作為 body 返回,不正是 JavaScript 高階函數(shù)的意思嗎?

可見,現(xiàn)在很多我們覺得稀松平常的一些用法,其實早在近 100 年前就被提出來了,不可謂不震撼。

三、JavaScript 的基因

說了半天,終于來到了我們的 JavaScript,相信大家接觸 JavaScript 之初都會被“閉包”這個概念搞得有點蒙,為什么要這樣設計?我平常又確實用不上,好不容易學了個防抖、節(jié)流函數(shù),你就不要再繼續(xù)追問“什么是閉包了”。

兄弟,有福了,這次帶你見識最初的閉包是如何產(chǎn)生的!

閉包的概念,在計算機誕生之前就被設計出來了,沒錯,還是來源于我們的 lambda 演算。

lambda 演算規(guī)定:

如果一個標識符是一個閉合 lambda 表達式的參數(shù),我們則稱這個標識符是被綁定的;如果一個標識符在任何封閉的上下文中都沒有綁定,那么它被稱為自由變量。

比如:

lambda x . plus x y

在這個表達式中,x是被綁定的,因為它是函數(shù)定義的閉合表達式 plus x y 的參數(shù)。而 y 是自由變量;

再比如:

lambda y . (lambda x . plus x y)

在內(nèi)層演算 lambda x . plus x y 中,x 是被綁定的,y 是自由的;而在完整表達中,x 和 y 是都是被綁定的:x 受內(nèi)層綁定,而 y 由剩下的外層演算綁定。

這正是 JavaScript 閉包最初的雛形, 內(nèi)部函數(shù)保持著對函數(shù)外部變量的引用。這里“被綁定的”意思就是變量不能被清理的,是以后會被用到的。

神奇嗎?閉包早于計算機誕生,仿佛就像打火機早于火柴發(fā)明一樣,讓人有點意外~

好了,最后說一說:為什么 JavaScript 基因里寫著函數(shù)式編程 ?

這一段歷史,應該很多工友早爛熟于心,網(wǎng)景公司想給 HTML 加一個腳本語言用于改善交互,于是招來了 布蘭登·艾克,這老哥 10 天就把這門語言的框架設計好了。它思想上基于 Self 語言和 Scheme 語言,語法上和 C 語言相似。

我們再看這里的 Scheme 語言,它其實就是一門堂堂正正的函數(shù)式編程語言,它是第一大函數(shù)式編程語言 Lisp (1958 年)兩種方言的其中一種。而 Lisp 則來源于 lambda 演算,來源于 丘奇,來源于那個解決 1900 年數(shù)學問題的意外收獲!

時間線是這樣的:

  • => 1900 年希爾伯特數(shù)學問題
  • => 1930 年丘奇 lambda 演算
  • => 1958 年 Lisp 語言
  • => 1975 年 Scheme 語言
  • => 1995 年 JavaScript 語言

知道從哪里來,才能知道往哪里去。

所以,朋友們,我們現(xiàn)在所用的 JavaScript,基因里有一個重要的組成部分是函數(shù)式,把函數(shù)放在第一位、關注輸入輸出、參數(shù)柯里化、高級函數(shù)等等,在近百年里逐漸演進。前段時間,看到一篇文章,JSON 之父吐槽說:現(xiàn)在我們更關注于把 JavaScript 的使用規(guī)模擴大,而不是關注怎樣使這門語言變得更好。然后導致他建議退役 JavaScript,我大受震撼?;蛟S,如果某一天,ES 版本迭代關注點只有:又新增了幾個語法糖,而忽略了這門語言最初的設計思想,忽略去完善它,那真有點可惜。

以上就是從歷史講起JavaScript基因里的函數(shù)式編程實例的詳細內(nèi)容,更多關于JavaScript基因函數(shù)式編程的資料請關注腳本之家其它相關文章!

相關文章

最新評論