本文是對函數式編程範式的系列文章從而拉開了與以下延續一個。 介紹 在JavaScript中,函數只是對象。因此,可以構造函數,作為參數傳遞,從函數返回或分配給變數。因此,JavaScript具有一流的功能。更準確地說,JavaScript支持以下內容: 高階函數參數 產生高階函數 嵌套函數 匿名功能 ...
本文是對函數式編程範式的系列文章從而拉開了與以下延續一個。
介紹
在JavaScript中,函數只是對象。因此,可以構造函數,作為參數傳遞,從函數返回或分配給變數。因此,JavaScript具有一流的功能。更準確地說,JavaScript支持以下內容:
- 高階函數參數
- 產生高階函數
- 嵌套函數
- 匿名功能
- 關閉
- 部分申請(ECMAScript 5)
通過函數表示數據
我們S
是任何元素的集合a
,b
,c
...(例如,桌子上的書本或歐幾裡得平面的點),並讓S'
是這些元素的任意子集(例如,桌子上的書本綠色或點半徑1的圓心以歐幾里德平面的原點為中心)。
所述特征函數 S'(x)
的一組S'
是其中任一相關聯的功能true
或false
與每個元件x
的S
。
S'(x) = true if x is in S' S'(x) = false if x is not in S'
讓我們S
成為桌子上的一套書,讓我們S'
成為桌上的綠色書籍。設a
和b
是兩個綠色的書,讓c
和d
是在表中的兩個紅本本。然後:
S'(a) = S'(b) = true S'(c) = S'(d) = false
讓S
是集的歐幾里德平面中的點,並且讓S'
在半徑為1的在歐幾裡得平面(0,0)的原點為中心的圓的組的點的(單位圓)。讓a
和b
在單位圓的兩點,並讓c
並且d
是在歐幾裡得平面的原點為中心的半徑2的圓的兩點。然後:
S'(a) = S'(b) = true S'(c) = S'(d) = false
因此,任何集合S'
總是可以由其特征函數表示。一個函數,它將一個元素作為參數,true
如果該元素在S'
,false
則返回,否則返回。換句話說,可以通過JavaScript中的函數表示集合(抽象數據類型)。
function set() { }
在接下來的部分中,我們將看到如何通過JavaScript以函數方式表示集合代數中的一些基本集合,然後我們將在集合上定義泛型二進位運算。然後,我們將在歐幾里德平面的子集上對數字應用這些操作。集合是抽象數據結構,數字的子集和歐幾裡得平面的子集是抽象數據結構的表示,最後二元操作是適用於抽象數據結構的任何表示的通用邏輯。
JavaScript環境
要運行網站源碼,您需要一個JavaScript引擎。有很多JavaScript引擎可用。在本節中,我將逐步介紹如何使用Ubuntu 16.04中的V8 JavaScript引擎來設置JavaScript環境。V8是一個用C ++編寫的開源JavaScript引擎,用於谷歌Chrome,Node.js和V8.NET。設置也可以在Windows和macOS上完成。
- 獲取V8源代碼並編譯它:
我通過在終端中運行以下命令,在Ubuntu 16.04上成功安裝並執行了d8。
sudo apt-get install git mkdir ~/js cd ~/js git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git depot_tools export PATH=~/js/depot_tools:"$PATH" fetch v8 cd v8 make native ~/js/v8/out/native/d8
從git存儲庫下載V8源代碼需要一些時間,具體取決於Internet連接速度。編譯V8源代碼也需要一些時間,具體取決於硬體配置,但在等待必要的時間後,一切正常。
- 我們可以編寫第一個JavaScript代碼:
要在控制臺中載入JavaScript文件,可以按如下方式執行:
load('set.numbers.demo.js')
集
本節通過JavaScript介紹集合代數中一些基本集的表示。
空集
讓E
是空集和Empty
它的特色功能。在集合的代數中,E
是沒有元素的唯一集合。因此,Empty
可以定義如下:
Empty(x) = false if x is in E Empty(x) = false if x is not in E
因此,E
JavaScript中的表示可以定義如下:
empty = function() {return function(){return false}}
在集合的代數中,Empty
表示如下:
因此,運行以下代碼:
print('\nEmpty set:')
print('Is 7 in {}? ' + empty()(7))
給出以下結果:
全部設定
我們S
是一組和S'
是的子集S
,它包含所有要素,All
其特色功能。在集合的代數中,S'
是包含所有元素的完整集合。因此,All
可以這樣定義:
All(x) = true if x is in S
因此,S'
JavaScript中的表示可以定義如下:
all = function() {return function(){return true}}
在集合的代數中,All
表示如下:
因此,運行以下代碼:
print('\nSet All:')
print('Is 7 in integers set? ' + all()(7))
給出以下結果:
單身套裝
我們E
是辛格爾頓集和Singleton
它的特色功能。在集合的代數中,E
也稱為單位集合,或者1元組是具有恰好一個元素的集合e
。因此,Singleton
可以定義如下:
Singleton(x) = true if x is e Singleton(x) = false if x is not e
因此,E
JavaScript中的表示可以定義如下:
singleton = function(x) {return function(y){return x === y}}
因此,運行以下代碼:
print('\nSingleton set:')
print('Is 7 in the singleton set {0}? ' + singleton(0)(7))
print('Is 7 in the singleton set {7}? ' + singleton(7)(7))
給出以下結果:
其他套裝
本節介紹整數集的子集。
偶數
我們E
是一組連號,並且Even
它的特色功能。在數學中,偶數是一個2的倍數。因此,Even
可以定義如下:
Even(x) = true if x is a multiple of 2 Even(x) = false if x is not a multiple of 2
因此,E
JavaScript中的表示可以定義如下:
even = function(x){return x%2 === 0}
因此,運行以下代碼:
print('\nEven numbers set:')
print('Is 99 in even numbers set? ' + even(99))
print('Is 998 in even numbers set? ' + even(998))
給出以下結果:
奇數
我們E
是一組奇數的和Odd
它的特色功能。在數學中,奇數是一個不是2的倍數的數字。因此,Odd
可以定義如下:
Odd(x) = true if x is not a multiple of 2 Odd(x) = false if x is a multiple of 2
因此,E
JavaScript中的表示可以定義如下:
odd = function(x){return x%2 === 1}
因此,運行以下代碼:
print('\nOdd numbers set:')
print('Is 99 in odd numbers set? ' + odd(99))
print('Is 998 in odd numbers set? ' + odd(998))
給出以下結果:
倍數為3
我們E
是一組3的倍數和MultipleOfThree
它的特色功能。在數學中,3的倍數是可被3整除的數。因此,MultipleOfThree
可以定義如下:
MultipleOfThree(x) = true if x is divisible by 3 MultipleOfThree(x) = false if x is not divisible by 3
因此,E
JavaScript中的表示可以定義如下:
multipleOfThree = function(x){return x%3 === 0}
因此,運行以下代碼:
print('\nMultiples of 3 set:')
print('Is 99 in multiples of 3 set? ' + multipleOfThree(99))
print('Is 998 in multiples of 3 set? ' + multipleOfThree(998))
給出以下結果:
倍數為5
我們E
是集合5的倍數和MultipleOfFive
它的特色功能。在數學中,5的倍數是可被5整除的數。因此,MultipleOfFive
可以定義如下:
MultipleOfFive(x) = true if x is divisible by 5 MultipleOfFive(x) = false if x is not divisible by 5
因此,E
JavaScript中的表示可以定義如下:
multipleOfFive = function(x){return x%5 === 0}
因此,運行以下代碼:
print('\nMultiples of 5 set:')
print('Is 15 in multiples of 5 set? ' + multipleOfFive(15))
print('Is 998 in multiples of 5 set? ' + multipleOfFive(998))
給出以下結果:
質數
很久以前,當我玩Project Euler問題時,我不得不解決以下問題:
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13. What is the 10 001st prime number?
為瞭解決這個問題,我首先必須編寫一個快速演算法來檢查給定的數字是否為素數。編寫演算法後,我編寫了一個迭代演算法,迭代遍歷素數,直到找到10 001 st素數。
我們E
是集合素數的和Prime
它的特色功能。在數學中,素數是大於1的自然數,除了1和自身之外沒有正除數。因此,Prime
可以定義如下:
Prime(x) = true if x is prime Prime(x) = false if x is not prime
因此,E
JavaScript中的表示可以定義如下:
prime = function(x){
if(x===1) return false
if(x<4) return true
if(x%2===0) return false
if(x<9) return true
if(x%3===0) return false
var sqrt = Math.sqrt(x)
for(var i = 5; i <= sqrt; i+=6){
if(x%i===0) return false
if(x%(i+2)===0) return false
}
return true
}
因此,運行下麵的代碼來解決我們的問題:
print('\nPrimes set:')
print('Is 2 in primes set? ' + prime(2))
print('Is 4 in primes set? ' + prime(4))
print('The 10 001st prime number is ' + getPrime(10001))
其中getPrime
定義如下:
getPrime = function(p){
var count = 0;
for(var i = 1; ; i++){
if(prime(i)) count++
if(count === p){
return i
break
}
}
}
給出以下結果:
二元操作
本節介紹了從給定集合和操作集合構造新集合的幾個基本操作。下麵是集合代數中的維恩圖。
聯盟
讓我們E
和F
兩套。該聯合的E
和F
,記為E U F
是一組其是成員的所有元素E
或F
。
讓我們Union
結合工會。因此,Union
可以在JavaScript中按如下方式實現操作:
union = function(e, f){return function(x){ return e(x) || f(x)}}
運行以下代碼:
print('\nUnion:')
print('Is 7 in the union of Even and Odd Integers Set? ' + union(even,odd)(7))
給出以下結果:
路口
讓我們E
和F
兩套。的交叉點的E
和F
,記為E n F
是一組這兩者都是成員的所有元素的E
和F
。
讓我們Intersection
進行交叉操作。因此,Intersection
可以在JavaScript中按如下方式實現操作:
intersection = function(e, f){return function(x){ return e(x) && f(x)}}
運行以下代碼:
print('\nIntersection:')
multiplesOfThreeAndFive = intersection(multipleOfThree, multipleOfFive)
print('Is 15 a multiple of 3 and 5? ' + multiplesOfThreeAndFive(15))
print('Is 10 a multiple of 3 and 5? ' + multiplesOfThreeAndFive(10))
給出以下結果:
笛卡爾積
讓我們E
和F
兩套。的笛卡兒積的E
和F
,由表示E × F
是該組所有有序對(e, f)
,使得e
是其成員E
和f
是其成員F
。
讓我們CartesianProduct
進行笛卡爾積運算。因此,CartesianProduct
可以在JavaScript中按如下方式實現操作:
cartesianProduct = function(e, f){return function(x, y){ return e(x) && f(y)}}
運行以下代碼:
print('\nCartesian Product:')
cp = cartesianProduct(multipleOfThree,multipleOfFive)
print('Is (9, 15) in MultipleOfThree x MultipleOfFive? ' + cp(9, 15))
給出以下結果:
補語
讓我們E
和F
兩套。的相對補的F
中E
,由表示E \ F
是一組其是成員的所有元件的E
但不是成員F
。
讓我們Complement
進行相對補充操作。因此,Complement
可以在JavaScript中按如下方式實現操作:
complement = function(e, f){return function(x){ return e(x) && !f(x)}}
運行以下代碼:
print('\nComplement:')
c = complement(multipleOfThree, multipleOfFive)
print('Is 15 in MultipleOfThree \\ MultipleOfFive set? '+ c(15))
print('Is 9 in MultipleOfThree \\ MultipleOfFive set? '+ c(9))
給出以下結果:
對稱差異
讓我們E
和F
兩套。的對稱差的E
和F
,記為E delta F
是一組其是的任成員的所有元素的E
和F
,但不是在相交E
和F
。
讓我們SymmetricDifference
進行對稱差分運算。因此,SymmetricDifference
可以在JavaScript中以兩種方式實現該操作。一個簡單的方法是使用union和補充操作如下:
symmetricDifferenceWithoutXor = function(e, f){ return function(x)
{ return union(complement(e,f), complement(f, e))(x)}}
另一種方法是使用XOR
二進位操作如下:
symmetricDifferenceWithXor = function(e, f){return function(x)
{ return (e(x) ^ f(x)) === 1 ? true : false}}
運行以下代碼:
print('\nSymmetricDifference without XOR:')
sdWithoutXor = symmetricDifferenceWithoutXor(prime, even)
print('Is 2 in the symetric difference of prime and even Sets? ' + sdWithoutXor(2))
print('Is 4 in the symetric difference of prime and even Sets? ' + sdWithoutXor(4))
print('Is 7 in the symetric difference of prime and even Sets? ' + sdWithoutXor(7))
print('\nSymmetricDifference with XOR:')
sdWithXor = symmetricDifferenceWithXor(prime, even)
print('Is 2 in the symetric difference of prime and even Sets? ', sdWithXor(2))
print('Is 4 in the symetric difference of prime and even Sets? ', sdWithXor(4))
print('Is 7 in the symetric difference of prime and even Sets? ', sdWithXor(7))
給出以下結果:
其他行動
本節介紹集合上其他有用的二進位操作。
包含
設Contains
是檢查元素是否在集合中的操作。此操作是一個函數,它將元素作為參數,true
如果元素在集合中則返回,false
否則返回。
因此,此操作在JavaScript中定義如下:
contains = function(e, x){return e(x)}
因此,運行以下代碼:
print('\nContains:')
print('Is 7 in the singleton {0}? ' + contains(singleton(0), 7))
print('Is 7 in the singleton {7}? ' + contains(singleton(7), 7))
給出以下結果:
加
讓我們Add
將一個元素添加到集合中的操作。此操作是一個函數,它將元素作為參數並將其添加到集合中。
因此,此操作在JavaScript中定義如下:
add = function(e, y){return function(x){ return x === y || e(x)}}
因此,運行以下代碼:
print('\nAdd:')
print('Is 7 in {0, 7}? ' + add(singleton(0),7)(7))
print('Is 0 in {1, 0}? ' + add(singleton(1),0)(0))
print('Is 7 in {19, 0}? ' + add(singleton(19),0)(7))
給出以下結果:
去掉
設Remove
是從集合中刪除元素的操作。此操作是一個函數,它將元素作為參數並將其從集合中刪除。
因此,此操作在JavaScript中定義如下:
remove = function(e, y){return function(x){ return x !== y && e(x)}}
因此,運行以下代碼:
print('\nRemove:')
print('Is 7 in {}? ' + remove(singleton(0), 0)(7))
print('Is 0 in {}? ' + remove(singleton(7), 7)(0))
給出以下結果:
對於那些想要更進一步的人
您可以通過函數式編程看到我們可以輕鬆地在JavaScript中使用集合代數。在前面的部分中,顯示了最基本的定義。但是,如果你想進一步,你可以考慮:
- 關係集
- 抽象代數,如么半群,群,場,環,K-矢量空間等
- 包含 - 排除原則
- 羅素的悖論
- 康托爾的悖論
- 雙向量空間
- 定理和推論
歐幾裡得飛機
在上一節中,集合的基本概念是在JavaScript中實現的。在本節中,我們將練習在平面點集(歐幾里德平面)上實現的概念。
繪製磁碟
磁碟是由圓圈限定的平面的子集。有兩種類型的磁碟。封閉的磁碟是包含構成其邊界的圓的點的磁碟,而打開的磁碟是不包含構成其邊界的圓的點的磁碟。
在本節中,我們將成立Characterstic功能的的封閉盤和HTML5繪製。
要設置Charactertic函數,首先需要一個計算平面中兩點之間歐氏距離的函數。該功能實現如下:
function distance(p1, p2){
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2))
}
其中point
定義如下:
point = function(x,y){
this.x = x
this.y = y
}
這個公式是基於畢達哥拉斯定理。
其中c
是歐幾里德距離,a²
是(p1.X - p2.X)²
和b²
是(p1.Y - p2.Y)²
。
我們Disk
是特色功能的封閉盤。在集合的代數中,實數集中的閉合磁碟的定義如下:
其中a
和b
是中心和R
半徑的坐標。
因此,Disk
JavaScript中的實現如下:
disk = function(center, radius){return function(p){ return distance(p, center) <= radius}}
為了查看集合,我決定實現一個draw
在歐幾裡得平面中繪製集合的函數。我選擇了HTML5,因此使用了canvas
元素進行繪製。
因此,我通過該方法建立了下麵說明的歐幾里德平面draw
。
下麵是飛機的實施。
/*
* Plane
*
*/
plane = function(width, height) {
/**
* Plane width in pixels
*
*/
this.width = width
/**
* Plane height in pixels
*
*/
this.height = height
/*
* Draws a generic set
*
*/
this.draw = function (set, canvasId){
var canvas = document.getElementById(canvasId)
canvas.width = this.width
canvas.height = this.height
var context = canvas.getContext('2d'),
semiWidth = this.width/2, semiHeight = this.height/2,
xMin = -semiWidth, xMax = semiWidth,
yMin = -semiHeight, yMax = semiHeight
for(var x = 0; x < this.width; x++){
var xp = xMin + x * (xMax - xMin) / this.width
for(var y = 0; y < this.height; y++) {
var yp = yMax - y * (yMax - yMin) / this.height
if(set(new point(xp, yp))) context.fillRect(x, y, 1, 1)
}
}
}
}
在該draw
方法中,創建canvas
具有與歐幾里德平面容器相同的寬度和相同高度的a 。然後(x,y)
,canvas
如果屬於的是黑點,則每個像素點都被替換為黑點set
。xMin
,xMax
,yMin
和yMax
是在的圖中所示的邊界值歐幾裡得平面的上方。
運行以下代碼:
euclideanPlane = new plane(200, 200)
euclideanPlane.draw(disk(new point(0, 0), 50), 'disk')
這裡disk
是id
帆布:
<canvas id="disk">Your browser does not support HTML5 canvas.</canvas>
給出以下結果:
繪製水平和垂直半平面
甲水平或垂直半平面或者是兩個子集到其中的平面將歐幾里德空間。甲水平半平面或者是兩個子集到其中的平面垂直通過與所述的線劃分的歐幾裡得空間的Y軸如上面的圖中。甲垂直半平面或者是兩個子集到其中的平面通過管線垂直與劃分歐幾裡得空間的X軸。
在本節中,我們將設置水平和垂直半平面的特征函數,在HTML5中繪製它們,看看如果我們將它們與磁碟子集組合,我們可以做些什麼。
我們HorizontalHalfPlane
是特色功能一的水平半平面。HorizontalHalfPlane
JavaScript中的實現如下:
horizontalHalfPlane = function(y, isLowerThan){return function(p)
{ return isLowerThan ? p.y <= y : p.y >= y}}
因此,運行以下代碼:
euclideanPlane.draw(horizontalHalfPlane(0, true), 'hhp')
這裡hhp
是id
帆布:
<canvas id="hhp">Your browser does not support HTML5 canvas.</canvas>
給出以下結果:
我們VerticalHalfPlane
是特色功能一的垂直半平面。VerticalHalfPlane
JavaScript中的實現如下:
verticalHalfPlane = function(x, isLowerThan){return function(p) { return isLowerThan ? p.x <= x : p.x >= x}}
因此,運行以下代碼:
euclideanPlane.draw(verticalHalfPlane(0, false), 'vhp')
這裡vhp
是id
帆布
<canvas id="vhd">Your browser does not support HTML5 canvas.</canvas>
給出以下源碼結果:
在本文的第一部分中,我們在集合上設置了基本的二進位操作。因此,通過組合a disk
和a 的交集half-plane
,我們可以繪製半盤子集。
因此,運行以下示例:
euclideanPlane.draw(intersection(disk(new point(0, 0), 50), verticalHalfPlane(0, false)), 'hd')
這裡hd
是id
帆布:
<canvas id="hd">Your browser does not support HTML5 canvas.</canvas>
給出以下結果:
功能
本節介紹歐幾里德平面上的集合的函數。
翻譯
我們translatePoint
是翻譯在平面上的點的功能。在歐幾里德幾何中,translatePoint
是一個將給定點在指定方向上移動恆定距離的函數。因此,JavaScript中的實現如下:
translatePoint = function(deltax, deltay){return function(p)
{ return new point(p.x + deltax, p.y + deltay)}}
其中(deltax, deltay)
是翻譯的常量向量。
我們translate
是轉化平面中的設定功能。這個函數在JavaScript中簡單地實現如下:
translate = function(e, deltax, deltay){return function(p)
{ return e(translatePoint(-deltax, -deltay)(p))}}
translate
取deltax
第一歐幾里德維度中的delta距離作為參數,其是deltay
第二歐幾里德維度中的delta距離。如果點P(x,y)在集合S中被平移,則其坐標將變為(x',y')=(x + delatx,y + deltay)。因此,點(X ' - delatx,Y' - DELTAY)將始終屬於集合小號。在集合代數中,translate
稱為同構,換句話說,所有翻譯的集合形成翻譯組T,其與空間本身同構。這解釋了該功能的主要邏輯。
因此,運行以下代碼:
var deltay = 0
setInterval(function(){
deltay = deltay <= euclideanPlane.height ? deltay + 20 : 0
euclideanPlane.draw(translate(disk(new point(0, -50), 50), 0, deltay) , 'ep_op')
}, 1000)
這裡ep_op
是id
帆布:
<canvas id="ep_op">Your browser does not support HTML5 canvas.</canvas>
給出以下結果:
位似
讓scalePoint
是發送的任何點的功能中號到另一點Ñ使得段SN是在同一行作為SM,而是由一個因數縮放拉姆達。在集的代數中,Scale
表述如下:
因此,JavaScript中的實現如下:
scalePoint = function(lambdax, lambday, deltax, deltay)
{return function(p){ return new point(lambdax * p.x + deltax, lambday * p.y + deltay)}}
其中(deltax, deltay)
是平移的常數向量,(lambdax, lambday)
是lambda向量。
讓我們scale
在計劃中的集合上應用同一性的功能。這個函數在JavaScript中簡單地實現如下:
scale = function(e, lambdax, lambday, deltax, deltay)
{return function(p){ return e(scalePoint(1/lambdax, 1/lambday,
-deltax/lambdax, -deltay/lambday)(p))}}
scale
取deltax
第一歐幾里德維度中的Δ距離作為參數,該第一歐幾里德維度deltay
是第二歐幾里德維度中的Δ距離,並且(lambdax, lambday)
是恆定因數向量λ。如果點P(x,y)scale
在集合S中變換,則其坐標將變為(x',y')=(lambdax * x + delatx,lambday * y + deltay)。因此,點((x'- delatx)/ lambdax,(y' - deltay)/ lambday)將始終屬於集合S,當然,如果lambda不同於向量0。在集合的代數中,scale
稱為同構,換句話說,所有同態的集合形成Homothety組H,與空間本身\ {0}同構。這解釋了該功能的主要邏輯。
因此,運行以下代碼:
var deltay = 0, lambday = 0.05
setInterval(function(){
deltay = deltay <= euclideanPlane.height ? deltay + 20 : 0
lambday = deltay <= euclideanPlane.height ? lambday + 0.05 : 0.05
euclideanPlane.draw(scale(disk(new point(0, -50), 50), 1, lambday, 0, deltay), 'ep_op')
}, 1000)
給出以下結果:
旋轉