From the functional point of view, the three major characteristics of object oriented defects (iOS)

Preface

I don’t know what you’ve been collecting. Most of my reading lists are functional programming related things: basically, it’s the most difficult to chew. These articles full of textbooks language very boring, I think even those steeped in Wall Street 10 years Daniel can understand these functional programming (FP). You can go to Citigroup or Deutsche Bank to find a project manager to ask 1: Why did you choose JMS instead of Erlang? The answer is basically: I don’t think the academic language is adequate for practical use. However, some of the existing systems are not only very complex, but also need to meet very stringent needs, and they are all implemented by functional programming. This is justified. The article about FP is really hard to understand, but I don’t think it must be so obscure. There are some historical reasons for this knowledge gap, but the concept of FP itself is not difficult to understand. I hope this article will be a “FP starter guide” that helps you move from directive programming to functional programming. I’ll have some coffee first, and then read on. Soon, your understanding of FP will impress your colleagues. What is functional programming (Functional, Programming, FP)? Where does it come from? Can I eat it? If it really is as good as those who preach FP, why is it so rare in practical applications? Why only the guys who are reading the doctor want to use it? And most of all, how could her mother be so hard to learn? What are the so-called “closure”, “continuation”, “currying”, “lazy”, “evaluation”, and “no side effects”? How can you apply it to actual projects without the help of those university professors? Why is it different from the universal and holy instruction programming that we are familiar with?

Functional concept

Also known as functional programming, is a programming paradigm, which treats computer operations as mathematical function calculations, and avoids the use of program states and mutable objects. The most important basis of the functional programming language is the lambda calculus. And the function of lambda calculus can be accepted as a function of the input (argument) and output (outgoing value).

Compared to imperative programming, functional programming more emphasis on program execution results rather than the implementation process, promote the use of some simple calculation results that the execution unit is gradual and continuous, complex operation layer, rather than to design a complex implementation process. The results are more important than the process.

The term “function” in functional programming is not a function (actually Subroutine) in a computer, but a function in mathematics, that is, the mapping of an independent variable. That is to say, the value of a function depends only on the value of the function parameter and does not depend on other states. For example, the sqrt (x) function computes the square root of X, and the value is constant whenever x is called and calls several times. Functional programming gives us another way of abstraction and reflection. Functional programming is a style that has nothing to do with programming languages. Object oriented is also a style that has nothing to do with programming languages. The two styles are not contradictory and can be combined – functional object (Objects, in, OCaml)

Functional property

  • Closures, also known as lexical closures (Lexical, Closure), function closures (function, closures), or Lambdas expressions, are functions that refer to free variables. This referenced free variable will exist with this function, even if it has left the environment that created it. So there is another view that closures are entities made up of functions and their reference environment. Corresponds to the Blocks in the OC language. Closures can be understood as anonymous functions, and the following example will use closures a lot. When you read code, use Block as a function. Because closures perform operations only when called, that is, lazy evaluation, they can be used to define control structures. .
  • Lazy evaluation execution order is not dependent on statement order, and is more complicated. Functional programming languages also provide monadification (Lazy evaluation, also known as call-by-need), is in the expression assigned to the variable (or binding) does not calculate the value of the expression, and the variable is first used to calculate. This allows you to improve performance by avoiding unnecessary evaluation. Specific understanding of reference closures. .
  • Function is the “first citizen” of the so-called “first class citizens” (first class), refers to the same function with other data types, are of equal status, can be assigned to other variables, but also can be used as a parameter, the introduction of another function, or else returned as the value of the function. Relatively easy to understand without illustration. .
  • Higher order functions are functions whose arguments are functions or return values as functions. The phenomenon is the function into an object like spread, like flying. With higher order functions, the granularity of reuse can be reduced to the function level, and the granularity of reuse is lower than that of object-oriented languages. At this point we focus on the relationship between functions and functions. 举例来说,假设有如下的三个函数, // 例子1: typedef NSInteger(^BlockFun)(NSInteger); BlockFun retSelf = ^(NSInteger a){ return a;}; BlockFun square = ^(NSInteger a){ return a*a;}; BlockFun cube = ^(NSInteger a){ return a*a*a;}; NSInteger sumInt(NSInteger a, NSInteger b){ if (a > b) return 0; return (a + sumInt(a + 1, b)); } NSInteger sumSquare(NSInteger a, NSInteger b){ if (a > b) return 0; return (square(a) + sumSquare(a + 1, b)); } NSInteger sumCube(NSInteger a, NSInteger b){ if (a > b) return 0; return (cube(a) + sumCube(a + 1, b)); } 分别是求a到b之间整数之和,求a到b之间整数的平方和,求a到b之间整数的立方和。 The difference between the three functions is that the fun is different, so can you abstract a common pattern? We can define a higher order function sumWithFun:NSInteger sumWithFun (BlockFun fun, NSInteger a, NSInteger b) {if (a > B return 0; return (fun) (a) + sumWithFun (fun, a + 1, b));} where the parameter fun is a function call function in fun function calculation, calculated. Then 1 examples can be simplified as follows: / / typedef NSInteger example of 1: (^BlockFun) (NSInteger); BlockFun = retSelf ^ (NSInteger a) {return a;}; BlockFun = square ^ (NSInteger a) {return a*a;}; BlockFun = cube ^ (NSInteger a) {return}; a* a*a; NSInteger sumWithFun (BlockFun fun, NSInteger a, NSInteger b) {if (a > B return 0; return (fun) (a) + sumWithFun (fun, a + 1, b));} / / call mode NSInteger a = 10, B = 20; NSLog (@%ld,%ld,%ld “(sumWithFun, retSelf, a, b), sumWithFun (square, a, b), sumWithFun (cube, a, b)); so you can reuse the sumWithFun function to achieve three functions in the sum logic.
    (example source: https://d396qusza40orc.cloudfront.net/progfun/lecture_slides/week2-2.pdf) high order function provides a function on the level of dependency injection (or reverse control) mechanism, in the above example, the sumWithFun function of the logical function to inject in logic. Many GoF design patterns can be implemented using higher order functions such as Visitor, Strategy, Decorator, and so on. For example, the Visitor model can be replaced by the map () or foreach () higher order functions of a collection class. .
  • Continuation only half of our understanding of the function is correct, because this understanding is based on a false assumption: the function must return its return value to the caller. In this understanding, continuation is a more generalized function. The function here does not necessarily return the return value to the caller; instead, it can pass the return value to any code in the program. Continuation is a special parameter that passes this parameter to the function, and the function can pass the return value to a part of the program based on the continuation. Very profound, but not so complicated. Take a look at the following example: int i = add (5, 10); int j = square (I); add, this function returns 15, and then this value is assigned to I, which is where add is called. Next, the value of I will be used to call square again. Note that the compiler that supports lazy evaluation does not disrupt the execution order of the code because the execution of the second functions relies on the first function to successfully execute and return the result. This code can be rewritten with Continuation Pass Style (CPS) technology, so that the return value of add is not passed to its caller, but directly to square. Int j = add (5, 10, square); in this case, add more than one parameter: a function, add must complete their calculation, call this function and sends the result to it. At this point, square is a add of continuation. In the previous two procedures, the value of J is 225. In this way, we learned the first technique for executing two expressions sequentially in imperative lazy languages. Let’s look at the following IO program (which is not a bit familiar?) System.out.println (“Please enter name: your”); System.in.readLine (); the two lines of code have no dependencies on each other, so the compiler can rearrange their execution sequence at will. But if you rewrite it with CPS, the compiler must execute sequentially because the overridden code has dependencies. System.out.println (Please, enter, your, name:, System.in.readLine);
  • Currying (local call (partial application)) is the function definition: Wikipedia transform accept multiple parameters to accept a single parameter (the first parameter initial function) function, and return the remaining parameters and new function returns the result of technology. When a function is not required for all incoming parameters, it will return to another function (the returned function record which has parameters), this situation is called currying. Intuitively, currying claimed that “if you fix some parameters, you will get a function of remaining parameters”.
    , such as the power function pow (x, y), takes two arguments — X and y, and calculates x^y. The use of currying technology, y can be fixed to 2 into the square function only accept a single parameter x, or y will be fixed for 3 into cubic function. The code is as follows: / / square function double (^SquareFun) (double) ^ (double = a) {return pow (a, 2);}; / / cubic function double (^CubeFun) (double) ^ (double = a) {return pow (a, 3);}; familiar with design patterns of friends have been feeling to do is currying function (Interface) package, it will be an existing function (Interface) for package, get a new function (Interface), the adapter pattern (Adapter pattern) the idea is consistent. Why should we currying: delay calculation. The above example has been well illustrated. Parameter reuse. When multiple calls to the same function, and most of the transfer parameters are the same, then the function may be a good candidate of curry. Dynamic creation function. This can be done in part after calculating the results, and on this basis, a new function is dynamically generated to process the business behind, thus omitting repeated computations. Or you can be a subset of parameters to a function call, part of the application to function, so as to create a new dynamic function, the new function preserved parameter incoming (after every time pass).
Thinking: high order function examples sumWithFun how to curry?
  • Using expressions only, without a statement, an expression (expression) is a purely arithmetic process that always has a return value; the statement (statement) performs some sort of operation without returning the value. Functional programming requires that expressions are used only, and statements are not used. That is to say, each step is a simple operation and has a return value. The reason for this is the motivation for functional programming, starting with computation, without considering I/O. “Statements” are read and write operations on the system, so they are excluded. Of course, in practice, it is impossible not to do I/O. Thus, in programming, functional programming requires only I/O to be minimal, without unnecessary read and write behavior, and maintain the simplicity of the computation process. Everything is expression thinking: if B then 100 else 10, this is not a conditional jump, but a three yuan expression that returns 100 or 10. .
  • A point on the non modified state has already been mentioned. Functional programming simply returns new values without modifying system variables. Therefore, without modifying variables, it is also an important feature of it.
    in other types of languages, variables are often used to hold state. Not modifying variables means that status cannot be saved in variables. Functional programming uses parameters to preserve the state, and the best example is recursion. The following code is a function in which strings are arranged in reverse order, which demonstrates how different parameters determine the state of the operation”. Let a = 100 means that instead of assigning 100 to the variable a, instead of binding the a symbol (or called a match) to 100. Since the value of a variable is immutable, the value of the operation does not modify the original value, but rather modifies the newly generated value, which makes the original value inconvenient. For example, a Point class whose moveBy method does not change the X and Y coordinate values of existing Point instances, but returns a new Point instance. Class Point (x: Int, y: Int) {override def (toString) = Point (“+ X +”, “+ y +”) “def moveBy (deltaX: Int, deltaY: Int) {new = Point (x + deltaX, y + deltaY)}} (source: Anders Hejlsberg in echDays sample 2010 speech) also due to variable immutable, pure functional programming language can not achieve circulation, this is because the For loop uses a variable state as the counter, while While or DoWhile loop to variable state conditions as out of circulation. So in functional languages, recursion can only be used to solve iterative problems, which makes functional programming heavily dependent on recursion. I usually have a recursive algorithm (iterative) and recursive (recursive) two definitions, using factorial as an example, the recursive definition of factorial:
    calculated recursively defined
    factorial recursive definition of the need to use an accumulator to keep each iteration of the intermediate results, the C code is as follows: static int fact (int n) {int ACC = 1; for (int k = 1; k = < n; k++) {ACC = ACC * k return ACC;};} and calculate the recursive definition of C code is as follows: int fact (int n) {if (n = = 0) return 1 return n * fact (n-1)} we can see, do not use the cycle, without the use of variable, function more short, do not need to explicitly use the accumulator save intermediate results, but the use of n parameter (allocated on the stack) to hold intermediate results.
    (sample source: 1., Recursion)
  • Pipeline is the technical means, the function instance into a action, then, a set of action into an array or list, and sends the data to the action data list, like a pipeline like sequence by each function operation, finally get the result we want. The StringFunCompose function is as follows. Typedef NSString* (^StringBlock) (NSString*); StringBlock = ToUpperCase ^ (NSString*str) {return}; [str uppercaseString]; StringBlock = Excailm ^ {return (NSString*str) [str “stringByAppendingString:@!”];}; / readability is not good, let the code run from right to left, not from the inside operation StringBlock = ^ Shout (NSString* STR) {return Excailm (ToUpperCase (STR));}; StringBlock StringFunCompose (NSArray*blocks) ^ {return (NSString* STR) {NSEnumerator * enumerator = [blocks reverseObjectEnumerator]; StringBlock block; while (block = [enumerator nextObject]) {STR = block (STR);}}}; return str; void (sampleCurry (@ NSLog) {“[sampleCurry]”); NSLog (@ “% @ Shout @ (” Let'”. S get started with FP “)); NSLog (@”% @ “, StringFunCompose (@[Excailm, ToUpperCase]) (Let’s get started with @” FP “));} Torgovnik

Function and object oriented, process oriented differentiation

Object oriented programming is also a command programming.

Imperative programming is a computer oriented hardware abstraction, a variable (corresponding to a storage unit), assignment (acquisition, storage, expression (instruction) memory references and arithmetic) and control statements (jump instruction), a word, a sequence of instructions Von Neumann machine is imperative programs. Object oriented is just a different way of modeling, and essentially a command programming.

Wikipedia said that functional programming is a declarative programming. Sound Ming programming is the opposite of imperative programming.

  • Abstract thinking of functional programming about data mapping, imperative programming about the transformation process, the data step function to solve the problem with A-> B-> C-> D-> E; object oriented, I should consider, what are the objects, each object for which the process function, process between how to cooperate.
  • Variables are stateless, not assigned, and variables in a purely functional programming language are not variables in imperative programming languages, that is, units that store States, but variables in algebra, that is, the name of a value. The value of a variable is immutable (immutable), that is to say, a variable is not allowed to be assigned as many times as in a command programming language. For example, in command programming languages, we write “x = x + 1”, which relies on mutable facts to show to the programmer that it is true, but to mathematicians, it is assumed that the equation is false. .

Advantages of functions

  • There is no “side-effect” called “effect” (side), which refers to the interaction between the inside and outside of the function (the most typical case is to modify the value of the global variable) and produce other results other than the operation.
    functional programming emphasizes the absence of “side-effect”, which means that the function must remain independent, and all functions return a new value, with no other behavior, especially the value of the external variable. .
  • Function reference is pure and transparent, transparent function reference (Referential transparency), which is a function of the operation is not dependent on external variables or “state”, only depends on the input parameters, whenever the same parameters, citing the resulting function return value is always the same. With no modification of variables, this is obvious. In other languages, the return value of a function is often related to the system state, and the return value is different under different states. This is called “opaque reference”, which is very harmful to observing and understanding the behavior of the program. .
  • Portability / self documenting (Portable / Self-Documenting) due to the function of the variable, so the portability is good; the pure function is completely self-sufficient, everything it needs can be obtained easily. Think carefully and think about this… What are the benefits of this self-sufficiency? First, the dependencies of pure functions are explicit, so it is easier to observe and understand – there are no sneaky little moves. .
  • The code is simple, the development of fast function programming, a large number of functions, reducing the duplication of code, so the program is relatively short, faster development. .
  • The granularity of reuse is minimal, and the function is smaller and functions in units. .
  • Close to natural language, easy to understand, high degree of freedom of functional programming, you can write very close to natural language code. The expression was (1 + 2) * 3 – 4, written language function: subtract (multiply (add (1,2), 3), 4) deformation of it, you can get another method: add (1,2).Multiply (3).Subtract (4). This is the basic natural language the expression of the. Look at the code below, and you should know what it means at a glance: merge ([1,2], [3,4]),.Sort (),.Search (“2”)
  • Easy to test, not prone to error function that is not dependent on external state does not modify the external condition, time and location of the result of the function call does not depend on the call, so easy to write code for reasoning, not easy to make a mistake. This makes unit testing and debugging easier. The state of the program is not good, and it is more difficult to maintain when it is concurrent. (you can imagine that if your program has a complex state, it’s easy to bug when someone changes your code later, and that’s more of a problem in parallel.)
  • Easy to “concurrent programming” functional programming does not need to consider deadlock, because it does not modify variables, so there is no lock thread problem. There is no need to worry that a thread’s data is modified by another thread, so you can safely distribute the work to multiple threads and deploy concurrent programming (concurrency). Please see the following code: VAR S1 = Op1 (VaR); S2 = Op2; S3 = concat (VaR) (S1, S2); because S1 and S2 do not interfere with each other, do not modify the variables, who first execution does not matter, we can safely increase the thread, allocate them into finished in two a thread. Other types of language can not do this, because S1 may modify the state of the system, and S2 may be used in these States, so must ensure that S2 is running on the S1, nature also cannot be deployed to other threads. Multicore CPU is the trend of the future, so this feature of functional programming is important. .
  • The code’s thermal update, functional programming, has no side effect. As long as the interfaces are kept unchanged, the internal implementation is externally independent. Therefore, you can upgrade the code directly in the running state, without restarting or stopping. The Erlang language has long been the proof that Ericsson, a Swedish Ericsson company, developed the management of the telephone system, and that the upgrade of the telephone system is, of course, impossible to stop. .

The shortcoming of function formula

  • Not good at handling mutable States and IO, handling mutable States, and handling IO, either introducing mutable variables or encapsulating them via Monad (such as State, Monad, and IO Monad). System.out.println (“Please enter your name:”); System.in.readLine (); in an inert language, no one can guarantee the execution of the second row in the first row! This also means that we cannot handle IO, call the system function cannot do anything useful (these functions need to follow the order of execution, because they depend on the external condition), that can not interact with the outside world! If we introduce code primitives that support sequential execution in code, then we lose the advantage of mathematically analyzing code processing (and that means losing all the advantages of functional programming). .

Object oriented from the functional point of view

We look at the definition of Wikipedia in declarative programming: declarative programming is to tell the computer need to calculate what not how to calculate any no side effects of the programming language, or rather, any reference transparent programming language any strict calculation logic programming language I’ve personal understanding of the three the characteristics of the first two is to imitate the human way of thinking. Because human thinking depends largely on intuition, humans do not know how they come up with answers. So declarative programming languages don’t specify how a computer can execute commands. Because human beings are stubborn, it is difficult to modify the concepts in mind. So declarative programming also mimics humans and does not allow you to modify variables. The third point is the good wish of the pioneer of artificial intelligence, thinking like human beings, but don’t make mistakes like human beings.

  • Abstract patterns require collaboration between objects, resulting in complex relationships between objects and poorly arranged. Recommendation: -[x] can abstract functions into objects, but abstractions are based on mappings of data objects, each of which implements only its own functions and does not have any coupling with other objects. A node on a
    -[x] flowchart is abstracted into an object, and eventually an object or function is responsible for connecting all the objects together to complete the whole process. At this point, you can clearly see the entire process from this object or function
  • Three characteristics of package poor readability, difficult debugging object-oriented package to the class variable, and then used to operate the function, the member variables in the scope of the entire class, need to consider the variable with the change of time. Resulting in poor readability and difficulty in debugging. Some suggestions: to minimize the use of member variables, variable scope to a minimum API is difficult to use because the function and class member variable coupling, may need to call other function before calling a function, if the order is wrong, it may lead to abnormal. Recommendation: -[x] tries to make every function do not reference member variables and global variables, so that the function has no side effects and references transparency. The
    -[x] interface class simply responds to user events and displays data. Try not to have logic.

.

  • Inheritance requires understanding the relationships between classes at inheritance levels, poor readability, and difficult to understand when the inheritance hierarchy is greater than 3 layers. The range of variables and functions is enlarged, and the coupling degree becomes larger, and the readability is further reduced. Extend the scope of the function, resulting in some function covering problems. Recommendation: -[x] does not use classes
-[x] uses less inheritance, or does not inherit, uses inheritance, the hierarchy tries not to exceed 3 layers, -[x] uses more combinations, and less inheritance
  • Polymorphism debugging is difficult, and you need to run to determine which functions the specific class implements. Recommendation: -[x] use of higher-order functions and currying to achieve differentiation

Why is there so much merit in functional programming that is not popular?

  • At first it was only for mathematical calculations, and some scenarios were not implemented, and therefore not suitable for practical work applications, especially for interface processing. But it also uses functions to implement interfaces, such as OM
  • Because of the large amount of recursion used, the compiler didn’t do the optimizations at that time, resulting in slow running.

Not only is the oldest functional language Lisp rejuvenated, but new functional languages emerge, such as Erlang, clojure, Scala, F#, and so forth. The current most popular Swift, C++, Objective-C, C#, Python, Ruby, Javascript, the functional programming support is very strong, even the old Java object oriented and process oriented PHP, adding to the anonymous function support hastened to all. More and more evidence suggests that functional programming is no longer the favorite in academia, and has begun to tap into the industry. Perhaps, after object-oriented programming, functional programming will become the next mainstream programming paradigm (paradigm). Programmers in the future will probably have to know more or less. Java is also trying to reform progress, as function of “evolution”, for example java8 Stream stream, lambda, efforts will be promoted to a function (method) and other citizens, transparent Stream, no state of revealing the function of thought. Although Java’s FP may now be the extreme expression of OOP, it also expresses the advantages and future trends of FP from another aspect. Author: Accelerator link: https://www.zhihu.com/question/30190384/answer/142902047 source: know that the copyright is owned by the author. For commercial reprint, please contact the author for authorization. Please refer to the source for non commercial reprint.

Now popular, personally think there are several reasons:

  • Computer hardware, multi-core technology development, so that performance is no longer a bottleneck
  • Advances in the FP compiler
  • In the mobile Internet era, the era of distributed and concurrent applications has finally arrived
  • Open source libraries, ReactiveCocoa, RxJava, and front-end Redux use a large number of functional programming ideas.
  • Big data, the development of artificial intelligence leads to only data processing.