History
TheConcepts
A number of concepts and paradigms are specific to functional programming, and generally foreign to imperative programming (including object-oriented programming). However, programming languages often cater to several programming paradigms, so programmers using "mostly imperative" languages may have utilized some of these concepts.First-class and higher-order functions
Higher-order functions are functions that can either take other functions as arguments or return them as results. In calculus, an example of a higher-order function is the differential operator , which returns the derivative of a function . Higher-order functions are closely related to first-class functions in that higher-order functions and first-class functions both allow functions as arguments and results of other functions. The distinction between the two is subtle: "higher-order" describes a mathematical concept of functions that operate on other functions, while "first-class" is a computer science term for programming language entities that have no restriction on their use (thus first-class functions can appear anywhere in the program that other first-class entities like numbers can, including as arguments to other functions and as their return values). Higher-order functions enable partial application or currying, a technique that applies a function to its arguments one at a time, with each application returning a new function that accepts the next argument. This lets a programmer succinctly express, for example, the successor function as the addition operator partially applied to the natural number one.Pure functions
Pure functions (or expressions) have no side effect (computer science), side effects (memory or I/O). This means that pure functions have several useful properties, many of which can be used to optimize the code: * If the result of a pure expression is not used, it can be removed without affecting other expressions. * If a pure function is called with arguments that cause no side-effects, the result is constant with respect to that argument list (sometimes called referential transparency or idempotence), i.e., calling the pure function again with the same arguments returns the same result. (This can enable caching optimizations such as memoization.) * If there is no data dependency between two pure expressions, their order can be reversed, or they can be performed in parallelization, parallel and they cannot interfere with one another (in other terms, the evaluation of any pure expression is thread-safe). * If the entire language does not allow side-effects, then any evaluation strategy can be used; this gives the compiler freedom to reorder or combine the evaluation of expressions in a program (for example, using deforestation (computer science), deforestation). While most compilers for imperative programming languages detect pure functions and perform common-subexpression elimination for pure function calls, they cannot always do this for pre-compiled libraries, which generally do not expose this information, thus preventing optimizations that involve those external functions. Some compilers, such as GNU Compiler Collection, gcc, add extra keywords for a programmer to explicitly mark external functions as pure, to enable such optimizations. Fortran 95 also lets functions be designated ''pure''. C++11 addedconstexpr
keyword with similar semantics.
Recursion
Iteration (looping) in functional languages is usually accomplished via recursion. recursion (computer science), Recursive functions invoke themselves, letting an operation be repeated until it reaches the Recursion (computer science), base case. In general, recursion requires maintaining a Call stack, stack, which consumes space in a linear amount to the depth of recursion. This could make recursion prohibitively expensive to use instead of imperative loops. However, a special form of recursion known as tail recursion can be recognized and optimized by a compiler into the same code used to implement iteration in imperative languages. Tail recursion optimization can be implemented by transforming the program into continuation passing style during compiling, among other approaches. The Scheme language standard requires implementations to support proper tail recursion, meaning they must allow an unbounded number of active tail calls. Proper tail recursion is not simply an optimization; it is a language feature that assures users that they can use recursion to express a loop and doing so would be safe-for-space. Moreover, contrary to its name, it accounts for all tail calls, not just tail recursion. While proper tail recursion is usually implemented by turning code into imperative loops, implementations might implement it in other ways. For example, Chicken (Scheme implementation), CHICKEN intentionally maintains a stack and lets the stack overflow. However, when this happens, its Garbage collection (computer science), garbage collector will claim space back, allowing an unbounded number of active tail calls even though it does not turn tail recursion into a loop. Common patterns of recursion can be abstracted away using higher-order functions, with catamorphisms and anamorphisms (or "folds" and "unfolds") being the most obvious examples. Such recursion schemes play a role analogous to built-in control structures such as Program loops, loops in imperative languages. Most general purpose functional programming languages allow unrestricted recursion and are Turing complete, which makes the halting problem undecidable problem, undecidable, can cause unsoundness of equational reasoning, and generally requires the introduction of inconsistency into the logic expressed by the language's type system. Some special purpose languages such as Coq allow only well-founded recursion and are strongly normalizing (nonterminating computations can be expressed only with infinite streams of values called codata (computer science), codata). As a consequence, these languages fail to be Turing complete and expressing certain functions in them is impossible, but they can still express a wide class of interesting computations while avoiding the problems introduced by unrestricted recursion. Functional programming limited to well-founded recursion with a few other constraints is called total functional programming.Strict versus non-strict evaluation
Functional languages can be categorized by whether they use ''strict (eager)'' or ''non-strict (lazy)'' evaluation, concepts that refer to how function arguments are processed when an expression is being evaluated. The technical difference is in the denotational semantics of expressions containing failing or divergent computations. Under strict evaluation, the evaluation of any term containing a failing subterm fails. For example, the expression: print length([2+1, 3*2, 1/0, 5-4]) fails under strict evaluation because of the division by zero in the third element of the list. Under lazy evaluation, the length function returns the value 4 (i.e., the number of items in the list), since evaluating it does not attempt to evaluate the terms making up the list. In brief, strict evaluation always fully evaluates function arguments before invoking the function. Lazy evaluation does not evaluate function arguments unless their values are required to evaluate the function call itself. The usual implementation strategy for lazy evaluation in functional languages is graph reduction. Lazy evaluation is used by default in several pure functional languages, including Miranda (programming language), Miranda, Clean (programming language), Clean, and Haskell. argues for lazy evaluation as a mechanism for improving program modularity through separation of concerns, by easing independent implementation of producers and consumers of data streams. Launchbury 1993 describes some difficulties that lazy evaluation introduces, particularly in analyzing a program's storage requirements, and proposes an operational semantics to aid in such analysis. Harper 2009 proposes including both strict and lazy evaluation in the same language, using the language's type system to distinguish them.Type systems
Especially since the development of Hindley–Milner type inference in the 1970s, functional programming languages have tended to use typed lambda calculus, rejecting all invalid programs at compilation time and risking false positives and false negatives#False positive error, false positive errors, as opposed to the untyped lambda calculus, that accepts all valid programs at compilation time and risks false positives and false negatives#False negative error, false negative errors, used in Lisp and its variants (such as Scheme), as they reject all invalid programs at runtime when the information is enough to not reject valid programs. The use of algebraic datatypes makes manipulation of complex data structures convenient; the presence of strong compile-time type checking makes programs more reliable in absence of other reliability techniques like test-driven development, while type inference frees the programmer from the need to manually declare types to the compiler in most cases. Some research-oriented functional languages such as Coq, Agda (theorem prover), Agda, Cayenne (programming language), Cayenne, and Epigram (programming language), Epigram are based on intuitionistic type theory, which lets types depend on terms. Such types are called dependent types. These type systems do not have decidable type inference and are difficult to understand and program with. But dependent types can express arbitrary propositions in higher-order logic. Through the Curry–Howard isomorphism, then, well-typed programs in these languages become a means of writing formal mathematical proofs from which a compiler can generate formal verification, certified code. While these languages are mainly of interest in academic research (including in formalized mathematics), they have begun to be used in engineering as well. Compcert is a compiler for a subset of the C (programming language), C programming language that is written in Coq and formally verified. A limited form of dependent types called generalized algebraic data types (GADT's) can be implemented in a way that provides some of the benefits of dependently typed programming while avoiding most of its inconvenience. GADT's are available in the Glasgow Haskell Compiler, inReferential transparency
Functional programs do not have assignment statements, that is, the value of a variable in a functional program never changes once defined. This eliminates any chances of side effects because any variable can be replaced with its actual value at any point of execution. So, functional programs are referentially transparent. Consider C (programming language), C assignment statementx = x * 10
, this changes the value assigned to the variable x
. Let us say that the initial value of x
was 1
, then two consecutive evaluations of the variable x
yields 10
and 100
respectively. Clearly, replacing x = x * 10
with either 10
or 100
gives a program a different meaning, and so the expression ''is not'' referentially transparent. In fact, assignment statements are never referentially transparent.
Now, consider another function such as Data structures
Purely functional data structures are often represented in a different way than their imperative programming, imperative counterparts. For example, the array data structure, array with constant access and update times is a basic component of most imperative languages, and many imperative data-structures, such as the hash table and binary heap, are based on arrays. Arrays can be replaced by Map (computer science), maps or random access lists, which admit purely functional implementation, but have logarithmic access and update times. Purely functional data structures have Persistent data structure, persistence, a property of keeping previous versions of the data structure unmodified. In Clojure, persistent data structures are used as functional alternatives to their imperative counterparts. Persistent vectors, for example, use trees for partial updating. Calling the insert method will result in some but not all nodes being created.Comparison to imperative programming
Functional programming is very different from imperative programming. The most significant differences stem from the fact that functional programming avoids side effect (computer science), side effects, which are used in imperative programming to implement state and I/O. Pure functional programming completely prevents side-effects and provides referential transparency. Higher-order functions are rarely used in older imperative programming. A traditional imperative program might use a loop to traverse and modify a list. A functional program, on the other hand, would probably use a higher-order “map” function that takes a function and a list, generating and returning a new list by applying the function to each list item.Imperative vs. functional programming
The following two examples (written in JavaScript (programming language), JavaScript) achieve the same effect: they multiply all even numbers in an array by 10 and add them all, storing the final sum in the variable "result". Traditional Imperative Loop:Simulating state
There are tasks (for example, maintaining a bank account balance) that often seem most naturally implemented with state. Pure functional programming performs these tasks, and I/O tasks such as accepting user input and printing to the screen, in a different way. The pure functional programming language Haskell implements them using monad (functional programming), monads, derived from category theory. Monads offer a way to abstract certain types of computational patterns, including (but not limited to) modeling of computations with mutable state (and other side effects such as I/O) in an imperative manner without losing purity. While existing monads may be easy to apply in a program, given appropriate templates and examples, many students find them difficult to understand conceptually, e.g., when asked to define new monads (which is sometimes needed for certain types of libraries). Functional languages also simulate states by passing around immutable states. This can be done by making a function accept the state as one of its parameters, and return a new state together with the result, leaving the old state unchanged. Impure functional languages usually include a more direct method of managing mutable state. Clojure, for example, uses managed references that can be updated by applying pure functions to the current state. This kind of approach enables mutability while still promoting the use of pure functions as the preferred way to express computations. Alternative methods such as Hoare logic and uniqueness type, uniqueness have been developed to track side effects in programs. Some modern research languages use effect systems to make the presence of side effects explicit.Efficiency issues
Functional programming languages are typically less efficient in their use of central processing unit, CPU and memory than imperative languages such as C (programming language), C and Pascal (programming language), Pascal. This is related to the fact that some mutable data structures like arrays have a very straightforward implementation using present hardware. Flat arrays may be accessed very efficiently with deeply pipelined CPUs, prefetched efficiently through caches (with no complex pointer chasing), or handled with SIMD instructions. It is also not easy to create their equally efficient general-purpose immutable counterparts. For purely functional languages, the worst-case slowdown is logarithmic in the number of memory cells used, because mutable memory can be represented by a purely functional data structure with logarithmic access time (such as a balanced tree). However, such slowdowns are not universal. For programs that perform intensive numerical computations, functional languages such asFunctional programming in non-functional languages
It is possible to use a functional style of programming in languages that are not traditionally considered functional languages. For example, both D (programming language), D and Fortran 95 explicitly support pure functions.functools
standard library module. First-class functions have been introduced into other mainstream languages such as PHP 5.3, Visual Basic 9, C# 3.0, C++11, and Kotlin.
In PHP, anonymous classes, Closure (computer science), closures and lambdas are fully supported. Libraries and language extensions for immutable data structures are being developed to aid programming in the functional style.
In Java (programming language), Java, anonymous classes can sometimes be used to simulate Closure (computer science), closures; however, anonymous classes are not always proper replacements to Closure (computer science), closures because they have more limited capabilities. Java 8 supports lambda expressions as a replacement for some anonymous classes.
In C#, anonymous classes are not necessary, because Closure (computer science), closures and lambdas are fully supported. Libraries and language extensions for immutable data structures are being developed to aid programming in the functional style in C#.
Many object-oriented Design pattern (computer science), design patterns are expressible in functional programming terms: for example, the strategy pattern simply dictates use of a higher-order function, and the visitor (design pattern), visitor pattern roughly corresponds to a catamorphism, or fold (higher-order function), fold.
Similarly, the idea of immutable data from functional programming is often included in imperative programming languages, for example the tuple in Python, which is an immutable array, and Object.freeze() in JavaScript.
Applications
Spreadsheets
Spreadsheets can be considered a form of pure, Higher-order function, zeroth-order, strict-evaluation functional programming system. However, spreadsheets generally lack higher-order functions as well as code reuse, and in some implementations, also lack recursion. Several extensions have been developed for spreadsheet programs to enable higher-order and reusable functions, but so far remain primarily academic in nature.Academia
Functional programming is an active area of research in the field of programming language theory. There are several peer-reviewed publication venues focusing on functional programming, including the International Conference on Functional Programming, the Journal of Functional Programming, and the Symposium on Trends in Functional Programming.Industry
Functional programming has been employed in a wide range of industrial applications. For example, Erlang, which was developed by the Sweden, Swedish company Ericsson in the late 1980s, was originally used to implement Fault tolerance, fault-tolerant telecommunications systems, but has since become popular for building a range of applications at companies such as Nortel, Facebook, Électricité de France and WhatsApp.1 million is so 2011Education
Many University, universities teach functional programming. Some treat it as an introductory programming concept while others first teach imperative programming methods. Outside of computer science, functional programming is used to teach problem-solving, algebraic and geometric concepts. It has also been used to teach classical mechanics, as in the book ''Structure and Interpretation of Classical Mechanics''.See also
* Purely functional programming * Comparison of programming paradigms * Eager evaluation * List of functional programming topics * Nested function * Inductive functional programming * Functional reactive programmingReferences
Further reading
* * Cousineau, Guy and Michel Mauny. ''The Functional Approach to Programming''. Cambridge, UK: Cambridge University Press, 1998. * Curry, Haskell Brooks and Feys, Robert and Craig, William. ''Combinatory Logic''. Volume I. North-Holland Publishing Company, Amsterdam, 1958. * * Dominus, Mark Jason.External links
* * An introduction * ''Functional programming in Python'' (by David Mertz)