摘要:以此類推,不定參數的方程也就被稱為可變參數函數。一般來說,函數式編程中的值都被認為是不可變值。實現了函數的對象,即可以與其他對象進行對比判斷是否屬于同一類型,被稱為。半群一個擁有,即將另一個對象轉化為相同類型的函數,函數的對象稱為。
Functional Programming Jargon:函數式編程術語解釋原文地址
譯者的Github 系列文章地址
本文原作者尚未全部完成,有興趣的可以到原文或者譯文地址關注更新
Arity:參數數目本文的主要目的即是希望能夠有一種通俗易懂的方式來闡述函數式編程中常見的理論術語概念
Arity代指一個函數的參數數量,該關鍵字來源于類似于unary、binary、ternary等等,由兩個后綴-ary、-ity組成。譬如,如果一個函數允許輸入兩個參數,那就稱為所謂的binary function(二元函數),或者一個有兩個參數的函數。有時候這種函數也會被喜歡拉丁語法的人稱為"dyadic(二價的)"函數。以此類推,不定參數的方程也就被稱為variadic(可變參數函數)。
const sum = (a, b) => a + b; const arity = sum.length; console.log(arity); // => 2 // The arity of sum is 2Higher-Order Functions (HOF):高等函數
一個接收某個函數作為參數的函數成為高等函數,該函數可以選擇返回一個函數也可以返回其他類型
const filter = (pred, xs) => { const result = []; for (var idx = 0; idx < xs.length; idx += 1) { if (pred(xs[idx])) { result.push(xs[idx]); } } return result; };
const is = type => x => Object(x) instanceof type;
filter(is(Number), [0, "1", 2, null]); //=> [0, 2]Partial Application:局部封裝
將原本一個多參數值的函數封裝為固定參數數目的函數的過程稱為Partial Application
let sum = (a, b) => a + b; // partially applying `a` to `40` let partial = sum.bind(null, 40); // Invoking it with `b` partial(2); //=> 42Currying
將一個N參數值的函數轉化為N個一元函數的組合,Currying與Partial Application的區別在于Partial Application最終生成的函數允許接收多個值,而Currying生成的函數序列中的每個函數只允許接收一個參數
let sum = (a, b) => a + b; let curriedSum = (a) => (b) => a + b; curriedSum(40)(2) // 42.Composition:組合
感覺有點像設計模式里的Decorator,即能夠將兩個指定類型組合轉化為一個新值的函數
最常見的組合即是常見的函數組合,允許你將不同的函數組合成一個返回單值的函數
const compose = (f, g) => a => f(g(a)) // Definition const floorAndToString = compose((val)=> val.toString(), Math.floor) //Usage floorAndToString(121.212121) // "121"Purity:純函數
一個沒有任何副作用,并且返回值只由輸入決定的函數成為純函數
let greet = "yo"; greet.toUpperCase(); // YO; greet // yo;
As opposed to:
let numbers = [1, 2, 3]; numbers.splice(0); // [1, 2, 3] numbers // []Side effects:副作用
如果一個函數,除了返回值之外,還會修改某些其它狀態,或者與外部函數等有可觀測的交互
console.log("IO is a side effect!");Idempotency:冪等性
多次執行下都不會產生副作用的函數被稱為具有冪等性的函數
f(f(x)) = f(x)
Math.abs(Math.abs(10))
Point-Free Style那些并沒有線性定義參數的函數風格被稱為Point-Free Style,這類型往往需要currying 或者 Higher-Order functions。
// Given let map = fn => list => list.map(fn); let add = (a, b) => a + b; // Then // Not points-free - `numbers` is an explicit parameter let incrementAll = (numbers) => map(add(1))(numbers); // Points-free - The list is an implicit parameter let incrementAll2 = map(add(1));
incrementAll明確規定了參數numbers, 而incrementAll2是對于參數的封裝,并沒有顯性說明numbers參數,因此它可以被稱為Points Free。一般來說,Points-free的函數都不會用常見的function或者=>關鍵字來定義。
Contracts 暫無 Guarded Functions 暫無 Categories:分類Value:值關聯到遵循某些規則的函數的對象,譬如monoid
計算中常用到的一些復合值(complex)或者簡單值(primitive),包括函數。一般來說,函數式編程中的值都被認為是不可變值。
5 Object.freeze({name: "John", age: 30}) // The `freeze` function enforces immutability. (a) => a
注意,譬如Functor, Monad這樣包含其他值的結構體本身也是值,這就是說,這些復合值也可以相互包含。
Constant:常量對于一個值的不可變引用,不能跟變量相混淆。Variable即指那些可能在任意點唄更改的引用。
const five = 5 const john = {name: "John", age: 30}
常量一般認為是透明的,也就是說,它們可以被值本身代替而不影響最終的計算結果,上面的兩個常量也可以用下述方式表述:
john.age + five === ({name: "John", age: 30}).age + (5)
上述表達式會一直返回真。
FunctorFunctor即指那些可以引用map函數的對象,JavaScript中最簡單的函數就是Array。
[2,3,4].map( n => n * 2 ); // [4,6,8]
假設func構造為一個實現了map函數的對象,f、g則是任意的函數,只要func遵循以下規則就可以將func稱為一個functor:
Let func be an object implementing a map function, and f, g be arbitrary functions, then func is said to be a functor if the map function adheres to the following rules:
func.map(x => x) == func
以及
func.map(x => f(g(x))) == func.map(g).map(f)
我們將Array稱為Functor,也是因為它遵循了以下規則:
[1, 2, 3].map(x => x); // = [1, 2, 3]
以及
let f = x => x + 1; let g = x => x * 2; [1, 2, 3].map(x => f(g(x))); // = [3, 5, 7] [1, 2, 3].map(g).map(f); // = [3, 5, 7]Pointed Functor
實現了of方法的Functor,Of會將任何單值轉化為一個Functor
Pointed Functor在Array中的實現為:
Array.prototype.of = (v) => [v]; [].of(1) // [1]Lift
Lift很類似于map,不過它可以用于多個Functors:
在單值函數下,Map與Lift的作用是一致的:
lift(n => n * 2)([2,3,4]); // [4,6,8]
而Lift可以允許輸入多個值:
lift((a, b) => a * b)([1, 2], [3]); // [3, 6]Referential Transparency:透明引用
一個可以直接用其值來替換而不會影響到程序表現的表達式稱為透明引用
譬如我們有一個叫greet的引用
let greet = () => "Hello World!";任何對于greet()的調用都可以被Hello World!直接替換,因此可以將greet稱為透明引用。 Equational Reasoning
Lazy evaluation:懶計算當一個應用由表達式組合而成并且沒有任何副作用的時候,該系統可以由部分推導而來
Lazy evaluation 即是所謂的只有在需要某個值的時候才進行計算的機制。在函數式語言中,這個機制就允許對于那些近乎無限的列表進行操作。
let rand = function*() { while(1<2) { yield Math.random(); } }
let randIter = rand(); randIter.next(); // Each exectuion gives a random value, expression is evaluated on need.Monoid:獨異點
一個monoid就是與某個恒等值進行組合之后不會影響現有結果的數據類型
一個最簡單的Monoid就是如下所示:
1 + 1; // 2
數據類型是number,函數是+:
1 + 0; // 1
恒等式的值是0,將0與任何數相加并不會改變值。有時候,monoid類型進行不同的交換操作也不會影響結果:
1 + (2 + 3) == (1 + 2) + 3; // true
數組連接也可以認為是一個monoid:
[1, 2].concat([3, 4]); // [1, 2, 3, 4]
恒等值即是空數組: []
[1, 2].concat([]); // [1, 2]Monad
一個Monad就是擁有of以及chain函數的對象。 Chain 類似于 map只不過它會扁平化最終求得的嵌套式結果。
["cat,dog","fish,bird"].chain(a => a.split(",")) // ["cat","dog","fish","bird"] //Contrast to map ["cat,dog","fish,bird"].map(a => a.split(",")) // [["cat","dog"], ["fish","bird"]]
You may also see of and chain referred to as return and bind (not be confused with the JS keyword/function...) in languages which provide Monad-like constructs as part of their standard library (e.g. Haskell, F#), on Wikipedia and in other literature. It"s also important to note that return and bind are not part of the Fantasy Land spec and are mentioned here only for the sake of people interested in learning more about Monads.
Comonad:余單子實現了extract與extend函數的對象
let CoIdentity = v => ({ val: v, extract: this.v, extend: f => CoIdentity(f(this)) })
Extract 可以將值從Functor中吐出來:
CoIdentity(1).extract() // 1
Extend則是會返回一個跟Commonad相同值的函數:
CoIdentity(1).extend(co => co.extract() + 1) // CoIdentity(2)Applicative(可適用的) Functor
一個Applicative Functor就是一個實現了ap函數的對象,Ap可以將某個對象中的某個值轉化為另一個對象中的相同類型的值
[(a)=> a + 1].ap([1]) // [2]Morphism:態射
Isomorphism:同態轉換一個轉化函數
用不同方式存儲的能夠表明相同數據的轉換
譬如,一個二維的數組可以存儲為數組:[2,3]或者對象:{x: 2, y: 3}。
// Providing functions to convert in both directions makes them isomorphic. const pairToCoords = (pair) => ({x: pair[0], y: pair[1]}) const coordsToPair = (coords) => [coords.x, coords.y] coordsToPair(pairToCoords([1, 2])) // [1, 2] pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2}Setoid
實現了equals函數的對象,即可以與其他對象進行對比判斷是否屬于同一類型,被稱為Setoid。
下面對于原型的擴充可以將Array變成Setoid。
Array.prototype.equals = arr => { var len = this.length if (len != arr.length) { return false } for (var i = 0; i < len; i++) { if (this[i] !== arr[i]) { return false } } return true } [1, 2].equals([1, 2]) // true [1, 2].equals([0]) // falseSemigroup:半群
一個擁有concat,即將另一個對象轉化為相同類型的函數,函數的對象稱為Semigroup。
[1].concat([2]) // [1, 2]Foldable:可折疊
實現了reduce函數,即可以將一個對象轉化為其他類型的函數,的對象稱為Foldable對象。
let sum = list => list.reduce((acc, val) => acc + val, 0); sum([1, 2, 3]) // 6Traversable 暫無 Type Signatures:類型簽名
一般來說,函數都會注釋表明它們的參數類型和返回值類型
// functionName :: firstArgType -> secondArgType -> returnType // add :: Number -> Number -> Number let add = x => y => x + y // increment :: Number -> Number let increment = x => x + 1
如果一個函數接收其他函數作為參數,譬如這樣:
// call :: (a -> b) -> a -> b let call = f => x => f(x)
這里的a, b, c, d表明參數可以是任意類型,不過它會將類型a轉化為另一個類型b,而對于下面這個map,它的注釋表明了它會輸入一個a類型的列表,然后轉化為另一個包含了b類型的列表。
// map :: (a -> b) -> [a] -> [b] let map = f => list => list.map(f)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79609.html
摘要:深入之繼承的多種方式和優缺點深入系列第十五篇,講解各種繼承方式和優缺點。對于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執行了。 JavaScript深入之繼承的多種方式和優缺點 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優缺點。 寫在前面 本文講解JavaScript各種繼承方式和優缺點。 但是注意: 這篇文章更像是筆記,哎,再讓我...
摘要:設計模式是以面向對象編程為基礎的,的面向對象編程和傳統的的面向對象編程有些差別,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續了解設計模式必須要先搞懂面向對象編程,否則只會讓你自己更痛苦。 JavaScript 中的構造函數 學習總結。知識只有分享才有存在的意義。 是時候替換你的 for 循環大法了~ 《小分享》JavaScript中數組的那些迭代方法~ ...
摘要:對象在中,除了數字字符串布爾值這幾個簡單類型外,其他的都是對象。那么在函數對象中,這兩個屬性的有什么區別呢表示該函數對象的原型表示使用來執行該函數時這種函數一般成為構造函數,后面會講解,新創建的對象的原型。這時的函數通常稱為構造函數。。 本文原發于我的個人博客,經多次修改后發到sf上。本文仍在不斷修改中,最新版請訪問個人博客。 最近工作一直在用nodejs做開發,有了nodejs,...
摘要:是完全的面向對象語言,它們通過類的形式組織函數和變量,使之不能脫離對象存在。而在基于原型的面向對象方式中,對象則是依靠構造器利用原型構造出來的。 JavaScript 函數式腳本語言特性以及其看似隨意的編寫風格,導致長期以來人們對這一門語言的誤解,即認為 JavaScript 不是一門面向對象的語言,或者只是部分具備一些面向對象的特征。本文將回歸面向對象本意,從對語言感悟的角度闡述為什...
摘要:函數式編程前端掘金引言面向對象編程一直以來都是中的主導范式。函數式編程是一種強調減少對程序外部狀態產生改變的方式。 JavaScript 函數式編程 - 前端 - 掘金引言 面向對象編程一直以來都是JavaScript中的主導范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數式編程越來越多得受到開發者的青睞。函數式編程是一種強調減少對程序外部狀態產生改變的方式。因此,...
閱讀 2679·2023-04-25 20:28
閱讀 1849·2021-11-22 09:34
閱讀 3687·2021-09-26 10:20
閱讀 1834·2021-09-22 16:05
閱讀 3085·2021-09-09 09:32
閱讀 2502·2021-08-31 09:40
閱讀 2101·2019-08-30 13:56
閱讀 3320·2019-08-29 17:01