preface

Before analyzing functional Programming, we need to clarify two leading concepts, namely: Programming Paradigm and Design Pattern:

Wikipedia defines Programming paradigms as follows:

Programming paradigms are a way to classify programming languages based on their features. Languages can be classified into multiple paradigms.

As you can see, the programming paradigm is a way of organizing code that is closely related to the characteristics of languages (especially language design and compilers).

Wikipedia defines Design patterns as follows:

In software engineering, a software design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design.

By definition, a design pattern is a generic solution, a programming paradigm is strongly related to the characteristics of a language, and a design pattern is a generic template that any language can implement according to its characteristics

From leading concept, we can know, functional programming is a programming paradigm, not a design pattern, which is strongly associated with the language, can be seen from the above, for programming paradigm can’t separate by an attribute or a border to distinguish it, especially the modern high-level language has borrowed from other language features and the method, therefore, At present, most of the distinguishing methods of programming methods in articles or textbooks are point-like analysis, because it is really difficult to distinguish clearly from the global, and common programming paradigms can be broadly divided into imperative programming and declarative programming. Imperative programming includes procedural programming and object-oriented programming (there is also said that object-oriented programming belongs to meta-programming), while declarative programming includes functional programming, logical programming and responsive programming. We can simply simplify the common programming paradigms into the classification shown in the figure above

concept

The first functional programming language is LISP, Schema language is a dialect of LISP language, and modern languages such as Haskell, Clean, Erlang, etc., have implemented the features of functional programming one after another. For front-end programmers, we use JavaScript or TypeScript, which is a superset of JavaScript and therefore a javascript-like language user. For JS, Brendan Eich is a fan of functional programming. Therefore, its design borrows from the concept of Schema’s function First Class (PS: The first citizen of the function, They can be bound to names (including local identifiers), passed as arguments, and returned from other functions, Just as any other data type can., that is, functions can bind by name, pass parameters, and return other functions), which fosters functional programming for JS. Since JS can achieve the characteristics of functional programming, so what are the characteristics of functional programming, or how to organize the code is functional programming?

In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions.

Wikipedia defines it as a programming paradigm that uses functions to compose and apply, so functions are at the heart of this paradigm, so what is a function? Let’s look at the theoretical basis of functions or functional programming in mathematics

function

Let F be a binary relation. If any X ∈ domF has a unique Y ∈ ranF that makes xFy valid, F is called a function. For F, if I have xFy, I’ll call it y = F(x), and I’ll call y the value of F at x.

It can be seen from the definition in Discrete Mathematics that the function is a special binary relation. Simply put, a function is a medium relation that connects two entities. In programming, it is common to have an input -> output relation. From this we can see that there is an expectation of what the input is and what the output is expected to be. Generally speaking, we only want to deal with the input and try not to affect or isolate the non-input. So when the output does not meet our expectation, that is, the output will affect the unexpected data of other input, Let’s say there’s a Side Effect; If the input can produce the same result at the same time, we call such a Function Pure Function, then the Pure Function will not bring any change to its execution environment. Let’s say that ideally the function is Referential Transparency to the environment.

Lambda calculus

Lambda calculus (also written as λ-calculus) is a formal system in Mathematical logic for Mathematics computation based on function abstraction and application using variable binding and substitution.

The λ calculus is a formal system (ps: in mathematical logic, the set of formal languages and their corresponding transformation rules is called a formal system) in which special forms are specified, such as α transformation and β specification: α transformation (PS: α-conversion, sometimes known as α-renaming,[21] allows variable names to be changed.), i.e. allows function calling entities (variable names, anchor identifiers) to be anonymous; In terms of substitution: the β-reduction of (λV.M) N is M[V := N]. In ES6, we use the lamda expression of the => arrow to implement the α transformation (this binding rule and arguments are cancelled) and the β specification (=> and function are replaced). According to this calculation form, different functions can be constructed. Common functional programming includes Curring Function, Partical Function, composing Function and other calculation forms, thus it can be seen that functional programming has the following characteristics: 1. Pipeline chain call; 2, lazy evaluation, lazy loading; 3, operator operation, hide internal details; 4. Immutable data.

MAO semigroup

Let V = < S, ο > be an algebraic system, at ο be a binary operation. With ο being combinable, V is called a semigroup. If E ∈ S is the unit element with reference to the operation ο, it is called the monoid, which is also called the unique point. The unique point V is also referred to as V = < S, ο, e >

Some category theory is involved here (PS: Is not rigorous, simply category theory is to distinguish, concept system and form category, also is to find the corresponding boundary, and have their own corresponding rules in this category and description) concept, here will be before says that extends the concept of function, said in front of the function type is a special kind of binary relation, and the group of some object is a binary operation, Among these objects, there is a special object E, which satisfies some laws (ps: not strict, simply understood as commutative law is a kind of rule), and is called identity element, also called identity element. Monoid defines the rules for binary operations of functions, which still return A after operation on element A.

functor

Let C and D be categories. A functor F from C to D is a mapping that: associates each object X in C to an Object F(X) in D; associates each morphism f: X -> Y in C to a morphism F(f): F(X) -> F(Y) in D such that the following two conditions hold: F(idx) = idF(x) for every object X in C, F(g ο f) = F(g) ο F(f) for all morphisms f: X -> Y and g: Y -> Z in C.

It can be seen from the definition that Functor has been extended in category theory, and its essence is the mapping relation between two categories

list

A monad on C consists of an endofunctor T:C -> C together with two natural fibres: η: Cofeo (8fbo) and cofeo (8fbo) and cofeo (8fbo) and cofeo (8fbo) and cofeo (8fbo) T2 -> T (where T2 is the functor T ο T from C to C). These are required to fulfill the following conditions (sometimes) Called coherence conditions): μ ο Tμ = μ ο μT (as natural observations T3 -> T); μ ο Tη = μ ο ηT = 1T (as natural T -> T; here 1T denotes the identify transformation from T to T).

By definition we can simply state that a monoid is a monoid on a category of a functor, where a functor is a functor that maps another category to itself. The core organization after all the functional fragmentation can be based on Monadic programming, which is also known as the Monadic development model.

Now that we know the underlying mathematical underpinning of front-end functional programming, let’s take a look at some front-end applications of functional programming

application

Application part identified several more representative library, designed to show the functional programming style and features, not to analyze all the source code, after all these libraries in the use of the method of programming is more than one, all of the methods are being to service, only the thought that counts, “” means” XingErShangZhe, XingErXiaZhe

jQuery

JQuery as an important js library, though it is now receding, but it is undoubtedly a milestone in the history of the front-end development significance of a representative, the deepest impact for jq we in addition to its help us on the simplified the dom manipulation, smoothing the part browser interface differences, actually the most influential of all its chain calls, Let’s look at how it is organized to implement this operation:

/ / https://github.com/jquery/jquery/tree/1.12-stable/src/core.js jQuery. Fn = jQuery. Prototype = {constructor: jQuery, selector: "", length: 0, toArray: function() {}, get: function(num) {}, map: function() {}, slice: function() {}, first: function() {}, last: function() {}, eq: function() {}, end: function() {} }Copy the code

Jq’s chained call does a duplicate of the name by constructor, using the js feature to loop the function

Redux

For Redux, compose and applyMiddleware are the ideal of functional programming

// https://github.com/reduxjs/redux/tree/master/src/compose.ts export default function compose(... funcs: Funcion[]) { if(funcs.length === 0) { return <T>(arg: T) => arg} if(funcs.length === 1) {return funcs[0]} // compose operation return funcs.reduce((a,b) => (... args:any) => a(b(... args))) }Copy the code
// https://github.com/reduxjs/redux/tree/master/src/applyMiddleware.ts export default function applyMiddleware( ... middlewares: Middleware[] ): StoreEnhancer<any> { return (createStore: StoreEnhancerStoreCreator) => <S, A extends AnyAction>( reducer: Reducer<S, A>, preloadedState? : PreloadedState<S> ) => { const store = createStore(reducer, preloadedState) const middlewareAPI: MiddlewareAPI = { getState: store.getState, dispatch: (action, ... args) => dispatch(action, ... Args)} // map const chain = middlewares. Map (Middleware => middleware(middlewareAPI)) dispatch = compose<typeof dispatch>(... chain)(store.dispatch) return { ... store, dispatch } } }Copy the code

React Hooks

React Hooks after React 16.8 give functional components more space and are more in line with React’s design philosophy of UI as data. Of course, React hooks took advantage of Fiber architecture to maximize functional concepts. Simple look at fragments of functional programming, specifically about the React the analysis of the hooks, can go out before the right look at the author wrote this article front-end | React hooks in SD – WAN in the project practice

// https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.new.js function updateReducer<S, I, A>( reducer: (S, A) => S, initialArg: I, init?: I => S ): [S, Dispatch<A>] { const hook = updateWorkInProgressHook(); const queue = hook.queue; queue.lastRenderedReducer = reducer; const current: Hook = (currentHook: any); let baseQueue = current.baseQueue; const pendingQueue = queue.pending; if (baseQueue ! == null) { const first = baseQueue.next; let newState = current.baseState; let newBaseState = null; let newBaseQueueFirst = null; let newBaseQueueLast = null; let update = first; // memoizedState = newState; hook.baseState = newBaseState; hook.baseQueue = newBaseQueueLast; queue.lastRenderedState = newState; } const dispatch: Dispatch<A> = (queue.dispatch: any); return [hook.memoizedState, dispatch]; }Copy the code

Reactive Extensions

Reactive Extensions are available on all platforms. The focus here is on rx.js, which belongs to Reactive Programming, but it will be combined with functional Programming to achieve functional Reactive Programming. Let’s take a quick look at its flatMap implementation:

// https://github.com/ReactiveX/rxjs/tree/master/src/internal/operators/flatMap.ts

export function mergeMap<T, R, O extends ObservableInput<any>>(
  project: (value: T, index: number) => O,
  resultSelector?: ((outerValue: T, innerValue: ObservedValueOf<O>, outerIndex: number, innerIndex: number) => R) | number,
  concurrent: number = Infinity
): OperatorFunction<T, ObservedValueOf<O> | R> {
  if (isFunction(resultSelector)) {
    // DEPRECATED PATH
    return mergeMap((a, i) => map((b: any, ii: number) => resultSelector(a, b, i, ii))(innerFrom(project(a, i))), concurrent);
  } else if (typeof resultSelector === 'number') {
    concurrent = resultSelector;
  }

  return operate((source, subscriber) => mergeInternals(source, subscriber, project, concurrent));
}
Copy the code

Lodash

Lodash is an industrial-grade library of tools that extends the original JS API for various operations. Let’s take a look at some implementations of its split elements:

// https://github.com/lodash/lodash/take.js function take(array, n=1) { if (! (array ! = null && array.length)) { return [] } return slice(array, 0, n < 0 ? 0 : n) }Copy the code

Ramda

As a js library for real Lamda calculus, it basically implements all the requirements of Lamda calculus

// https://github.com/ramda/ramda/tree/master/source/curryN.js export default function _curryN(length, received, fn) { return function() { var combined = []; var argsIdx = 0; var left = length; var combinedIdx = 0; while (combinedIdx < received.length || argsIdx < arguments.length) { var result; if (combinedIdx < received.length && (! _isPlaceholder(received[combinedIdx]) || argsIdx >= arguments.length)) { result = received[combinedIdx]; } else { result = arguments[argsIdx]; argsIdx += 1; } combined[combinedIdx] = result; if (! _isPlaceholder(result)) { left -= 1; } combinedIdx += 1; } return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn)); }; }Copy the code

conclusion

As a programming paradigm, the significance of functional programming not only lies in the specific implementation of business, but also lies in the development trend of the whole industry. Streaming rendering, front and back end ishomogeneous, combined with serverless, FAAS and other related, while providing some new access schemes related to big data such as Flink. I think this is the more forward-looking view of functional programming that is getting so much attention on the front end; At the same time, we should not depend on functional programming of transition, think that all code organization to functional programming is given priority to, so too much of a good thing, is not a good programming concept, as there is No Silver Bullet “software engineering (No Silver Bullet)”, all the methods and models is a service, the thought that counts, Method is only means, mutual encouragement!

reference

  • Front-end functional evolution
  • A guide to JavaScript functional programming
  • Discrete Mathematics (2nd Ed.)
  • Functional programming (PART 1)
  • Look at functional programming (part 2)
  • Category theory
  • Study notes on category theory
  • Category Theory Course
  • Category Theory
  • A brief history of category theory
  • Ten programming languages implement Y combinators
  • Writing high quality maintainable code: The programming paradigm
  • Talk about programming paradigms
  • Play with functional programming easily
  • Stanford CS107 Programming Paradigms
  • Programming paradigm
  • Software design pattern
  • JavaScript at 20
  • Functional programming introductory tutorial
  • Front end | React Hooks in SD – WAN in the project practice