📜 ⬆️ ⬇️

Functional programming jargon


Functional programming has many advantages, and its popularity is constantly growing. But, like any programming paradigm, the FP has its own jargon. We decided to make a small dictionary for everyone who is familiar with the OP.


The examples use javascript ES2015). ( Why javascript? )


Work on the material continues ; send your pull-requests to the original repository in English.


The document uses terms from the Fantasy Land spec specification as needed.


Arity


The number of function arguments. From the words unary, binary, ternary (unary, binary, ternary) and so on. This is an unusual word because it consists of two suffixes: "-ary" and "-ity.". Addition, for example, takes two arguments, so this is a binary function, or a function that has an arity equal to two. Sometimes the term "dyadic" (dyadic) is used if they prefer Greek roots instead of Latin ones. A function that takes an arbitrary number of arguments is called the variadic, respectively. But a binary function can take two and only two arguments, without regard to currying or partial application.


const sum = (a, b) => a + b const arity = sum.length console.log(arity) // 2 // The arity of sum is 2 

Higher-Order Functions (high order functions)


A function that takes a function as an argument and / or returns a function.


 const filter = (predicate, xs) => { const result = [] for (let idx = 0; idx < xs.length; idx++) { if (predicate(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)


Partial application of the function means the creation of a new function with the pre-filling of some of the arguments of the original function.


 // Helper to create partially applied functions // Takes a function and some arguments const partial = (f, ...args) => // returns a function that takes the rest of the arguments (...moreArgs) => // and calls the original function with all of them f(...args, ...moreArgs) // Something to apply const add3 = (a, b, c) => a + b + c // Partially applying `2` and `3` to `add3` gives you a one-argument function const fivePlus = partial(add3, 2, 3) // (c) => 2 + 3 + c fivePlus(4) // 9 

Also in JS, you can use Function.prototype.bind to partially apply the function:


 const add1More = add3.bind(null, 2, 3) // (c) => 2 + 3 + c 

Due to preliminary data preparation, partial application helps to create simpler and more complex functions. Functions with currying automatically perform partial applications.


Currying


The process of converting a function that takes several arguments to a function that takes one argument at a time.


For each function call, it takes one argument and returns a function that takes one argument until all arguments have been processed.


 const sum = (a, b) => a + b const curriedSum = (a) => (b) => a + b curriedSum(40)(2) // 42. const add2 = curriedSum(2) // (b) => 2 + b add2(10) // 12 

Auto Currying (automatic currying)


Transform a function that takes several arguments to a new function. If you pass a smaller number of arguments to the new function, it will return a function that accepts the remaining arguments. When the function receives the correct number of arguments, it is executed.


In Underscore, lodash and ramda there is a curry function.


 const add = (x, y) => x + y const curriedAdd = _.curry(add) curriedAdd(1, 2) // 3 curriedAdd(1) // (y) => 1 + y curriedAdd(1)(2) // 3 

Additional materials



Function Composition


Combining two functions to form a new function in which the output of the first function is the input of the second.


 const compose = (f, g) => (a) => f(g(a)) // Definition const floorAndToString = compose((val) => val.toString(), Math.floor) // Usage floorAndToString(121.212121) // '121' 

Purity


A function is pure if the value returned to it is determined solely by the input values, and the function has no side effects.


 const greet = (name) => 'Hi, ' + name greet('Brianne') // 'Hi, Brianne' 

Unlike:


 let greeting const greet = () => { greeting = 'Hi, ' + window.name } greet() // "Hi, Brianne" 

Side effects


A function has side effects if, in addition to returning a value, it interacts (reads or writes) with an external changeable state.


 const differentEveryTime = new Date() 

 console.log('IO is a side effect!') 

Idempotent (idempotency)


A function is idempotent if its repeated execution produces the same result.


 f(f(x))f(x) 

 Math.abs(Math.abs(10)) 

 sort(sort(sort([2, 1]))) 

Point-Free Style (Pointless Notation)


Writing functions in such a way that the definition implicitly indicates the number of arguments used. This style usually requires currying or another high-order function (or, in general, implicit programming).


 // Given const map = (fn) => (list) => list.map(fn) const add = (a) => (b) => a + b // Then // Not points-free - `numbers` is an explicit argument const incrementAll = (numbers) => map(add(1))(numbers) // Points-free - The list is an implicit argument const incrementAll2 = map(add(1)) 

The incrementAll function defines and uses the numbers parameter, so that it does not use pointless notation. incrementAll2 simply combines functions and values ​​without mentioning arguments. It uses no- point notation.


Definitions with no-point notation look like ordinary assignments without function or => .


Predicate (predicate)


A predicate is a function that returns true or false depending on the value passed. A common case of using a predicate is a callback function for an array filter.


 const predicate = (a) => a > 2 ;[1, 2, 3, 4].filter(predicate) // [3, 4] 

Categories


Objects with functions that obey certain rules. For example, monoids.


Value


Anything that can be assigned to a variable.


 5 Object.freeze({name: 'John', age: 30}) // The `freeze` function enforces immutability. ;(a) => a ;[1] undefined 

Constant (constant)


Variable that cannot be reassigned after definition.


 const five = 5 const john = {name: 'John', age: 30} 

Constants have referential transparency or referential transparency. That is, they can be replaced by the values ​​that they represent, and this will not affect the result.


With constants from the previous listing, the following expression will always return true .


 john.age + five === ({name: 'John', age: 30}).age + (5) 

Functor (functor)


An object that implements the map function, which, when traversing all values ​​in an object, creates a new object, and obeys two rules:


 //    (identity) object.map(x => x) === object 

and


 //   object.map(x => f(g(x))) === object.map(g).map(f) 

( f , g - arbitrary functions)


JavaScript has an Array functor because it obeys these rules:


 [1, 2, 3].map(x => x) // = [1, 2, 3] 

and


 const f = x => x + 1 const 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 (pointing functor)


An object with a of function with any value. In ES2015, there is Array.of , which makes arrays a pointing functor.


 Array.of(1) // [1] 

Lift


Lifting is when a value is placed in an object like a functor. If we "lift" (lift) a function into an applicative functor, then we can make it work with values ​​that are also present in the functor.


In some implementations, there is a function lift or liftA2 , which are used to simplify the launch of functions on functors.


 const liftA2 = (f) => (a, b) => a.map(f).ap(b) const mult = a => b => a * b const liftedMult = liftA2(mult) // this function now works on functors like array liftedMult([1, 2], [3]) // [3, 6] liftA2((a, b) => a + b)([1, 2], [3, 4]) // [4, 5, 5, 6] 

Raising a function with one argument and applying it does the same thing as map .


 const increment = (x) => x + 1 lift(increment)([2]) // [3] ;[2].map(increment) // [3] 

Referential Transparency


If an expression can be replaced with its value without affecting the program's behavior, then it has transparency of the links.


For example, there is a greet function:


 const greet = () => 'Hello World!' 

Any greet() call can be replaced with Hello World! so this function is transparent (referentially transparent).


Lambda (lambda)


An anonymous function that can be used as a value.


 ;(function (a) { return a + 1 }) ;(a) => a + 1 

Lambdas are often passed as arguments to higher order functions.


 [1, 2].map((a) => a + 1) // [2, 3] 

Lambda can be assigned to a variable.


 const add1 = (a) => a + 1 

Lambda Calculus (lambda calculus)


Informatics, in which functions are used to create a universal model of calculus .


Lazy evaluation


The calculation mechanism, if necessary, with a delay in the calculation of the expression until the value is required. In functional languages, this allows you to create structures like endless lists that are not normally possible in imperative programming languages, where the order of commands matters.


 const rand = function*() { while (1 < 2) { yield Math.random() } } 

 const randIter = rand() randIter.next() //     ,    . 

Monoid


An object with a function that "combines" an object with another object of the same type. A simple example of a monoid is the addition of numbers:


 1 + 1 // 2 

In this case, the number is an object, and + is a function.


There must be a neutral element (identity), so that combining the value with it does not change the value. In the case of addition, such an element is 0 .


 1 + 0 // 1 

It is also necessary that the grouping of operations does not affect the result (associativity):


 1 + (2 + 3) === (1 + 2) + 3 // true 

Concatenation of arrays is also a monoid:


 ;[1, 2].concat([3, 4]) // [1, 2, 3, 4] 

The neutral element is an empty array []


 ;[1, 2].concat([]) // [1, 2] 

If there are functions of a neutral element and composition, then the functions as a whole form a monoid:


 const identity = (a) => a const compose = (f, g) => (x) => f(g(x)) 

foo is any function with one argument.


 compose(foo, identity) ≍ compose(identity, foo) ≍ foo 

Monad


A monad is an object with the functions of and chain . chain is similar to map , but it decomposes nested objects as a result.


 // Implementation Array.prototype.chain = function (f) { return this.reduce((acc, it) => acc.concat(f(it)), []) } // Usage ;Array.of('cat,dog', 'fish,bird').chain((a) => a.split(',')) // ['cat', 'dog', 'fish', 'bird'] // Contrast to map ;Array.of('cat,dog', 'fish,bird').map((a) => a.split(',')) // [['cat', 'dog'], ['fish', 'bird']] 

of also known as return in other functional languages.
chain also known as flatmap and bind in other languages.


Comonad


An object with extract and extend functions.


 const CoIdentity = (v) => ({ val: v, extract () { return this.val }, extend (f) { return CoIdentity(f(this)) } }) 

Extract takes a value from the functor.


 CoIdentity(1).extract() // 1 

Extend performs a function on the board. The function should return the same type as the comonade.


 CoIdentity(1).extend((co) => co.extract() + 1) // CoIdentity(2) 

Applicative Functor (applicative functor)


An object with the ap function. ap applies a function in an object to a value in another object of the same type.


 // Implementation Array.prototype.ap = function (xs) { return this.reduce((acc, f) => acc.concat(xs.map(f)), []) } // Example usage ;[(a) => a + 1].ap([1]) // [2] 

This is useful when there are two objects, and you need to apply a binary operation on their contents.


 // Arrays that you want to combine const arg1 = [1, 3] const arg2 = [4, 5] // combining function - must be curried for this to work const add = (x) => (y) => x + y const partiallyAppliedAdds = [add].ap(arg1) // [(y) => 1 + y, (y) => 3 + y] 

As a result, we obtain an array of functions that can be called with ap to get the result:


 partiallyAppliedAdds.ap(arg2) // [5, 6, 7, 8] 

Morphism


Transformation function


Endomorphism (endomorphism)


A function whose input and output are of the same type.


 // uppercase :: String -> String const uppercase = (str) => str.toUpperCase() // decrement :: Number -> Number const decrement = (x) => x - 1 

Isomorphism (isomorphism)


A pair of structural transformations between two types of objects without data loss.


For example, two-dimensional coordinates can be stored in 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} 

Setoid


An object that has an equals function that can be used to compare objects of the same type.


Make an array a setoid:


 Array.prototype.equals = (arr) => { const len = this.length if (len !== arr.length) { return false } for (let i = 0; i < len; i++) { if (this[i] !== arr[i]) { return false } } return true } ;[1, 2].equals([1, 2]) // true ;[1, 2].equals([0]) // false 

Semigroup (semigroup)


An object with a concat function that combines it with another object of the same type.


 ;[1].concat([2]) // [1, 2] 

Foldable


An object in which there is a reduce function that transforms an object into another type.


 const sum = (list) => list.reduce((acc, val) => acc + val, 0) sum([1, 2, 3]) // 6 

Type Signatures (type signatures)


Often functions in JavaScript contain comments indicating the types of their arguments and return values. There are different approaches in the community, but they are all similar:


 // functionName :: firstArgType -> secondArgType -> returnType // add :: Number -> Number -> Number const add = (x) => (y) => x + y // increment :: Number -> Number const increment = (x) => x + 1 

If the function takes another function as an argument, then it is placed in parentheses.


 // call :: (a -> b) -> a -> b const call = (f) => (x) => f(x) 

The symbols a , b , c , d show that the arguments can be of any type. The next version of the map function accepts:


  1. a function that transforms a value of type a to another type b
  2. array of values ​​of type a ,

and returns an array of values ​​of type b .


 // map :: (a -> b) -> [a] -> [b] const map = (f) => (list) => list.map(f) 

Additional materials



Union type


The combination of two types in one, a new type.


There are no static types in JavaScript, but let's imagine that we invented the type NumOrString , which is the addition of String and Number .


The + operation in JavaScript works with strings and numbers, so you can use our new type to describe its input and output:


 // add :: (NumOrString, NumOrString) -> NumOrString const add = (a, b) => a + b add(1, 2) //   3 add('Foo', 2) //   "Foo2" add('Foo', 'Bar') //   "FooBar" 

A union type is also known as an algebraic type, a marked union, and a sum-type.


There are a couple of JavaScript libraries to define and use such types.


Product type


Type- product combines types in such a way that you are most likely familiar with:


 // point :: (Number, Number) -> {x: Number, y: Number} const point = (x, y) => ({x: x, y: y}) 

It is called the product, because the possible value of the data structure is the product (product) of different values.


See also: set theory .


Option (option)


Type-union with two cases: Some and None . Useful for composing functions that may not return values.


 // Naive definition const Some = (v) => ({ val: v, map (f) { return Some(f(this.val)) }, chain (f) { return f(this.val) } }) const None = () => ({ map (f) { return this }, chain (f) { return this } }) // maybeProp :: (String, {a}) -> Option a const maybeProp = (key, obj) => typeof obj[key] === 'undefined' ? None() : Some(obj[key]) 

Use chain to build a sequence of functions that return Option .


 // getItem :: Cart -> Option CartItem const getItem = (cart) => maybeProp('item', cart) // getPrice :: Item -> Option Number const getPrice = (item) => maybeProp('price', item) // getNestedPrice :: cart -> Option a const getNestedPrice = (cart) => getItem(obj).chain(getPrice) getNestedPrice({}) // None() getNestedPrice({item: {foo: 1}}) // None() getNestedPrice({item: {price: 9.99}}) // Some(9.99) 

Option also known as Maybe . Some sometimes called Just . None sometimes called Nothing .


JavaScript functional programming libraries



')

Source: https://habr.com/ru/post/310172/


All Articles