The original author of this article has not been completed, interested can go to the original or translation address to follow the update
The main purpose of this article is to provide an easy to understand way to explain common theoretical terminology concepts in functional programming
Arity: specifies the number of parameters
Arity refers to the number of arguments ina function. This keyword is derived from unary, binary, ternary, etc., and consists of -ary and -ity. For example, if a function allows two arguments, it is called a so-called binary function, or a function with two arguments. These functions are sometimes called “dyadic “by people who like Latin grammar. In the same way, equations with uncertain parameters are called variadic.
const sum = (a, b) => a + b;
const arity = sum.length;
console.log(arity);
// => 2
// The arity of sum is 2Copy the code
Higher-order Functions (HOF): higher-order Functions
A function that takes a function as an argument becomes an advanced function and can optionally return a function or another type
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;
};Copy the code
const is = type => x => Object(x) instanceof type;Copy the code
filter(is(Number), [0, '1', 2, null]); / / = > [0, 2)Copy the code
Partial Application: indicates Partial encapsulation
The process of encapsulating a multi-parameter function into a function with a fixed number of parameters is called 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); / / = > 42Copy the code
Currying
A function with N parameter values can be converted into a combination of N unary functions. The difference between a Partial Application and a Currying function is that a Partial Application can eventually generate a function that accepts multiple values. Each function in a sequence of functions that is curried can only take one argument
let sum = (a, b) => a + b;
let curriedSum = (a) => (b) => a + b;
curriedSum(40)(2) // 42.Copy the code
Combination of Composition:
It feels a bit like a Decorator in design mode, a function that converts a combination of two specified types to a new value
The most common combination is the common function combination, which allows you to combine different functions into a single function that returns a single value
const compose = (f, g) => a => f(g(a)) // Definition const floorAndToString = compose((val)=> val.toString(), Math.floor) //Usage floorAndToString(121.212121)Copy the code
Purity: pure functions
A function that has no side effects and whose return value is determined only by the input becomes a pure function
let greet = "yo";
greet.toUpperCase(); // YO;
greet // yo;Copy the code
As opposed to:
let numbers = [1, 2, 3];
numbers.splice(0); // [1, 2, 3]
numbers // []Copy the code
-sheldon: Well, there are Side effects
If a function, in addition to returning a value, modifies some other state, or has observable interactions with external functions, etc
console.log("IO is a side effect!" );Copy the code
Idempotency: idempotence
A function that is executed multiple times without side effects is said to be idempotent
f(f(x)) = f(x)
Math.abs(Math.abs(10))
Point-Free Style
A function Style that does not have linearly defined parameters is called point-free Style, and this type usually requires currying or 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));Copy the code
IncrementAll explicitly specifies the numbers parameter, and incrementAll2 encapsulates the parameters without explicitly specifying the numbers parameter, so it can be referred to as Points Free. In general, points-free functions are not defined with the usual function or => keyword.
Contracts
no
Guarded Functions
no
Classification of Categories:
Objects associated with functions that follow certain rules, such as monoid
Value: the Value
Complex or primitive values are commonly used in calculations, including functions. In general, values in functional programming are considered immutable.
5
Object.freeze({name: 'John', age: 30}) // The `freeze` function enforces immutability.
(a) => aCopy the code
Note that structures such as Functor and Monad that contain other values are themselves values, that is, these compound values can also contain each other.
Constant: Constant
An immutable reference to a value should not be confused with a variable. Variables are references that can be changed at any point.
const five = 5
const john = {name: 'John', age: 30}Copy the code
Constants are generally considered transparent, that is, they can be replaced by the values themselves without affecting the final result of the calculation. The two constants above can also be expressed as follows:
john.age + five === ({name: 'John', age: 30}).age + (5)
Copy the code
The above expression always returns true.
Functor
Functor is an object that can refer to a map function. The simplest function in JavaScript is Array.
[2,3,4]. Map (n => n * 2); / /,6,8 [4]Copy the code
Given that func is constructed as an object that implements a map function, and f and g are arbitrary functions, func can be called a functor as long as func follows the following rules: 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) == funcCopy the code
func.map(x => f(g(x))) == func.map(g).map(f)Copy the code
Array is called Functor because it follows the following rules:
[1, 2, 3].map(x => x); // = [1, 2, 3]Copy the code
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]Copy the code
Pointed Functor
Functor implements the of method, and of converts any single value to a Functor
The conservative Functor implementation in Array is:
Array.prototype.of = (v) => [v];
[].of(1) // [1]Copy the code
Lift
Lift is similar to Map, but it can be used with more than one Functors:
In single-valued functions, Map and Lift work in the same way:
Lift (n => n * 2)([2,3,4]); / /,6,8 [4]Copy the code
Lift allows you to enter multiple values:
lift((a, b) => a * b)([1, 2], [3]); / / [3, 6]Copy the code
Referential Transparency
An expression that can be replaced directly with its value without affecting program performance is called a transparent reference
For example, we have a reference called greet
let greet = () => "Hello World!" ;Copy the code
Any forgreet()
Can be calledHello World!
I can replace it directly, so I can replace itgreet
This is called a transparent reference.
Equational Reasoning
When an application is composed of expressions without any side effects, the system can be derived from parts
Lazy evaluation: Lazy evaluation
Lazy evaluation is a mechanism for calculating only when a value is needed. In functional languages, this mechanism allows operations on nearly infinite lists.
let rand = function*() { while(1<2) {="" yield="" math.random(); ="" }="" }<="" code="">Copy the code
let randIter = rand();
randIter.next(); // Each exectuion gives a random value, expression is evaluated on need.Copy the code
Monoid: Monoid
A monOID is a data type that, when combined with an identity value, does not affect the existing result
The simplest Monoid would look like this:
1 + 1; / / 2Copy the code
The data type is number and the function is + :
1 + 0; / / 1Copy the code
The value of the identity is 0, and adding 0 to any number does not change the value. Sometimes, monoid types do different swaps without affecting the result:
1 + (2 + 3) == (1 + 2) + 3; // trueCopy the code
An array join can also be thought of as a monoid:
[1, 2].concat([3, 4]); // [1, 2, 3, 4]Copy the code
Identity is an empty array: []
[1, 2].concat([]); / / [1, 2]Copy the code
Monad
A Monad is an object that has of and chain functions. Chain is like map except that it flattens out the nested result that you end up with.
['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']]Copy the code
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.
More than Comonad: list
An object that implements the extract and extend functions
let CoIdentity = v => ({
val: v,
extract: this.v,
extend: f => CoIdentity(f(this))
})Copy the code
Extract can spit values out of Functor:
CoIdentity(1).extract() // 1Copy the code
Extend returns a function that returns the same value as Commonad:
CoIdentity(1).extend(co => co.extract() + 1) // CoIdentity(2)Copy the code
“Applicative” is Functor
An Applicative Functor is an object that implements an AP function that converts a value in one object to a value of the same type in another object
[(a)=> a + 1].ap([1]) // [2]Copy the code
Morphism: Morphism
A transformation function
Isomorphism: homomorphism conversion
A transformation that represents the same data stored in different ways
For example, a two-dimensional array can be stored as array: [2,3] or object: {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}Copy the code
Setoid
An object that implements equals, which can be compared to other objects to determine whether they are of the same type, is called a Setoid.
The following extension to the prototype can change Array to 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]) // falseCopy the code
Semigroup: Semigroup
One has a concat, which converts another object into a function of the same type. The object of the function is called Semigroup.
[1].concat([2]) // [1, 2]Copy the code
Foldable: folding
Objects that implement the Reduce function, which translates an object into another type of function, are called Foldable objects.
let sum = list => list.reduce((acc, val) => acc + val, 0);
sum([1, 2, 3]) // 6Copy the code
Traversable
no
Type Signatures: Type Signatures
In general, functions are commented to indicate their parameter types and return value types
// functionName :: firstArgType -> secondArgType -> returnType
// add :: Number -> Number -> Number
let add = x => y => x + y
// increment :: Number -> Number
let increment = x => x + 1Copy the code
If a function takes other functions as arguments, for example:
// call :: (a -> b) -> a -> b
let call = f => x => f(x)Copy the code
The a, b, c, and D here indicate that the parameter can be of any type, but it will convert type A to another type B, whereas for the map below, its comments indicate that it will enter a list of type A and then convert it to another list containing type B.
// map :: (a -> b) -> [a] -> [b]
let map = f => list => list.map(f)Copy the code