Although users typically treat Python as a process and object-oriented language, it actually contains each of the things required to implement full function programming. This article discusses the conventional concepts of function programming and describes how to implement function technology in Python.
We are best starting from the hardest problem: "What is the function programming (FP)?" A answer may say that fp is you in use, for example, Lisp, Scheme, Haskell, ML, Ocaml, Clean, Mercury, Erlang (or other Some) The language is done when programming. This is a steady answer, but it is not necessary to clarify the problem. Unfortunately, even the function programmer is hard to have an uniform understanding of the FP. The story of "blind touch" is used to describe this situation seems appropriate. FPE is also able to confuse the FP with "command programming" (using, for example, C, PASCAL, C , Java, Perl, AWK, TCL, and many other languages, at least largely).
From a personal point of view, I will sketching the function to at least the following features. Since the language of the functionality makes these things simple, but makes other things difficult or impossible:
The function is the first class (object). That is, each of the operations that can be performed on "data" can be used to use the function itself (eg, pass a function to another function). Recursive use as the primary control structure. In some languages, there is no other "cycle" structure. The key focuses on list LIST processing (for example, name LISP). The list is often used with the recurrence of the child list to replace the loop. "Pure" function language can avoid side effects. This is not included in the most common mode in the command language, namely the first one, and then specifies the other value to the same variable to track the program status. FP does not encourage or do not allow statements, in order to replace the use of expressions (in other words, the function is added to the index). In purely, a program is an expression (plus the supported definition). FP is concerned about what is calculated instead of how to calculate. Many FPs take advantage of "higher level" functions (in other words, the function is a function operation, and these functions are in other function operations).
The advocate of function programming believes that all of these features lead to shorter development and less code. Moreover, high-level theoretists in computer science, logic and mathematics discovery proves that the formal performance of the function language and procedures is much easier than the command language and procedures.
Inherent Python Function Ability Since Python 1.0, Python has most of the FP features listed above. But for most Python features, they present in a very mixed language. To a large extent, because of the OOP characteristics of Python, you can ignore the rest (until you need it later). With Python 2.0, the list has added some great "phlegm of the flies". Although the list has not added any new capabilities, they make many old ability look much better.
The basic element of the FP in Python is a function map (), reduuce (), and filter (), and operator Lambda. In Python 1.x, the Apply () function is also very convenient to apply the list of a list of functions to another. Python 2.0 provides improved grammar for this purpose. It may be surprising, but few such functions (and basic operators) are almost sufficient to write any Python program; especially all stream control statements (IF, Elif, Else, Assert, Try, Except, Finally, for , Break, Continue, While, DEF) can use only FP functions and operators to function in function style. Although it actually eliminates all stream control commands in the program, it may only be useful to join "confusing python" competition (with code that looks like Lisp), but understands how FP is used to use functions and recursive stream control. The first thing that eliminates stream control statements should consider when we perform elimination contacts is the fact that Python "short circuit" is the real value of Boolean expressions. This provides an expression version of the IF / ELIF / ELSE block (assuming that each block calls a function, usually there is always possible to arrange this). Below is a specific method:
Listing 1. "Short Circuit" Condition in Python
# Normal Statement-Based Flow Control
IF
Elif
Else: func3 ()
# Quivalent "short circuit" Expression
(
# Xiple "short circuit" Expression
>>> x = 3
>>> DEFPR (s): return
>>> (x == 1 AND PR ('one')) or (x == 2 AND PR ('Two')) or ('kether'))
'other'
>>> X = 2
>>> (x == 1 AND PR ('one')) or (x == 2 AND PR ('Two')) or ('kether'))
'TWO'
The conditional call of the expression version seems to be a position; however, if we note that the Lambda operator must return to the expression, it is more interesting. Because - as indicated, the expression can be short-circuited, the LAMBDA expression is very common in the return value of the expression condition. Build on our example:
Listing 2. Python Lambda short circuit
>>> pr = lambda s: s
>>> Namenum = lambda x: (x == 1 And PR ("one")) /
.... or (x == 2 and PR ("Two")) /
.... or (Pr ("Other"))
>>> Namenum (1)
'One'
>>> Namenum (2)
'TWO' >>> Namenum (3)
'other'
The function as an example of the first type of object has shown a function of the first class in Python, but in a very subtle way. We have some fully conventional things when you create a function object using the Lambda operation. It is because of this, we can use the object with the name "Pr" and "Namenum", the method used by the name and the method of using the number 23 or string "SPAM" with these names. However, as we can use digital 23 without having to bind it with any name (in other words, the icon function is the same as the variable), we can use the function object created with Lambda without binding it with any name. A function is just another value we perform some operations in Python.
Our main operations performed by the first class object are to pass them to the FP built-in function MAP (), reduuce (), and filter (). Each of these functions accepted a function object as its first argument.
Map () performs a function that is passed on each of the corresponding items in the specified list, and returns the list of results. Reduce () is performed on each subsequent item, returning the internal accumulation of the final result; for example, RANGUCE (Lambda N, M: N * M, RANGE (1, 10)) means "10 steps" (change In order to multiply the product of the previous multiplication with each item). FILTER () uses the passing function to each item in the list, then returns the list of items that passed through the item passing the pass function test.
We also often pass function objects to their custom functions, but they are usually equivalent to the combination of the above-described built-in functions.
By combining these three FP built-in functions, you can perform an amazing series of "flow" operations (without using statements, only expressions).
The function cycle replacement cycle in Python is as simple as the replacement condition block. FOR can be converted directly to MAP (). For our conditions, we need to simplify the statement block into a single function call (we are gradually approaching the usual practice):
Listing 3. Function 'for' cycle in Python
For e in LST: Func (e) # statement-based loop
Map (Func, LST) # map () - based loop
In addition, there are similar techniques for functional methods of continuous program flow. That is, command programming usually contains approaching "to do this, then do that, then do other things." Map () let us do this:
Listing 4. Function continuous operation in Python
# let's create an execution utility function
Do_it = lambda f: f ()
# Let F1, F2, F3 (ETC) Be Functions That Perform Actions
Map (Do_IT, [F1, F2, F3]) # map () - BASED ACTION SEQUENCE
Typically, our entire MAIN program can be a MAP () expression and a function you need to perform in a series of completed programs. Another convenient feature of the first class function is that they can put them in a list.
While's conversion is slightly complicated, but still can be done directly:
Listing 5. Functions in Python 'While' cycle
# Statement-based While Loop
While
IF
Break
Else:
# Fp-style recursive while looppdefwhile_block ():
IF
Return 1
Else:
Return 0
While_fp = lambda: (
While_fp ()
While's conversion still requires the While_Block () function, it itself contains statements, not just expressions. But we need further elimination of this function (for example, short circuits for IF / ELSE in the template). In addition, because the circulatory body (according to the design) cannot change any variable,
Listing 6. Function 'echo' cycle in Python
# Imperative Version of "Echo ()"
Defecho_imp ():
While 1:
x = Raw_INPUT ("Imp -")
IF x == 'quit':
Break
Else
Print X
echo_imp ()
# u1ility function for "Identity with Side-Effect"
DEFMONADIC_PRINT (X):
Print X
Return X
# Fp version of "echo ()"
Echo_fp = lambda: monadic_print (Raw_INPUT ("fp -")) == 'quit' or echo_fp ()
echo_fp ()
What we have finished is trying to represent a small program involving I / O, cyclic and conditional statements into a recursive pure expression (actually, if desired, can represent function objects that can be passed to any other place). We really use the utility function Monadic_Print (), but this function is fully general, you can reuse each function program expression created later (it is a one-time cost). Note that any result of any expression that contains monadic_print (x) is the same, just like it contains only x. FP (especially Haskell) has a "single piece" for "no operation, there is a side effect in the process".
Eliminate side effects in removing the perfect, meaningful statement does not need to be in a messenger, nested expression, a very natural problem is: "Why ?!" I use Python all the descriptions of FP. Done. But the most important feature - may also be the most useful features in specific situations - it eliminates side effects (or at least some of the special fields, such as single body, and some contains). Most of the program errors - and how to resolve the programmer to resolve the debugging - because the variable contains an unexpected value during the program execution process. The function program only does not assign a variable allocation, thereby avoiding this special problem.
Let us see a quite ordinary command code. Its purpose is to print a list of several pairs of numbers than 25. The figures that make up each pair itself is selected from the other two lists. This operation is similar to the actual operation actually implemented in their program segment. The command method for achieving this is as follows: Listing 7. Command Python code for "Print University"
# Nested Loop Procedural Style for Finding Big Products
XS = (1, 2, 3, 4)
YS = (10, 15, 3, 22)
Bigmuls = []
# ... more stuff ...
For x in xs:
For y in ys:
# ... more stuff ...
IF x * y> 25:
Bigmuls.Append ((x, y))
# ... more stuff ...
# ... more stuff ...
Print Bigmuls
This project is too small, so that there is nothing possible. But our purpose may be embedded in the code of many other purposes. Those parts that use the "Morest" annotation are where the side effects can cause errors. Any of these places, variables XS, YS, Bigmuls, X, Y are likely to obtain an accident in the hypotheld. Moreover, all variables may have some values that may also be needed to have a later code after executing this segment code. Obviously, this type of error can be prevented using a function / instance form of encapsulation and consideration of the scope to prevent this type. Moreover, you can always be DEL after performing the emission. But in practice, these errors indicating the type are very common.
The function of the target completely eliminates these side effects. The following is a possible piece of code:
Listing 8. Function of "Print University" Python Code
Bigmuls = lambda xs, ys: filter (lambda (x, y): x * y> 25, Combine (XS, ys))
Combine = lambda XS, YS: Map (None, XS * LEN (YS), Dupelms (YS, LEN (XS)))))
Dupelms = Lambda LST, N: Reduce (Lambda S, T: S T, MAP (Lambda L, N = N: [L] * n, LST))
Print Bigmuls ((1, 2, 3, 4), (10, 15, 3, 22)))
In the example, we bind anonymous (Lambda) function object with the name, but this is not necessarily necessary. We can only nescery definitions. This is for readability purposes; but because Combine () is a good utility function that is available (all element pairs from two input lists). Subsequent Dupelms () is only a way to help Combine () play a role. Even if this function example is lessweight than the command example, once the utility function can be reused, the new code in bigmuls () itself may be less than the number of code in the command version.
This example of this function is that there is absolutely no variable to change any of these. There is no possibility of side effects that have not been expected in the later code (there will be no earlier code). Obviously, it does not have side effects that does not guarantee the correct code, but even this is the advantage. However, please note that Python (Different from many function languages) cannot prevent the name Bigmuls, Combine, and Dupelms' rebound. If combine () starts with other senses in the later part of the program, all efforts have worked hard. You can gradually create a Singleton class to include this type of non-variable binding (such as s.bigmuls et al.); But this column does not involve this.
One of the particular attention is that our specific purpose is to customize the new features in Python 2. The best (also function) technology is neither the command example provided above, nor a function instance, but: Listing 9. "Bigmuls" list Connotation Python code
Print [(x, y) for x in (1, 2, 3, 4) for y in (10, 15, 3, 22) IF x * Y> 25]
Conclusion I have introduced the method used by using the function equivalent to replace each Python stream control structure (the side effects are eliminated during the process). Effective conversion for a particular program will bring some additional considerations, but we already know that the built-in function is conventional and complete. In a later column, we will consider some more advanced function programming technology; hoping to explore more pros and cons of functionality.
Reference
Bryn Keller's "Xoltar Toolkit", which includes module Functional, which has added a lot of useful to Python's FP extension. Because the Functional module itself is fully written in Python, it has been possible in Python itself. But Keller also pointed out that a set of very closely integrated extensions, with many capabilities in the concise definition. Peter Norvig wrote an interesting article, Python for Lisp Programmers. But his focus is in contrast to my column, it provides a very good conventional comparison between Python and LISP. Comp.lang.Functional FAQ is to understand a good start of function programming. I found that it is easier to master function program by language Haskell than Lisp / Scheme (even if only in Emacs, the latter may be more wide). Other Python programmers can be much easier without using so many parentheses and prefixes. A very useful introductory book is Haskell: The Craft Of Functional Programming (2nd Edition), Simon Thompson (Addison-Wesley, 1999).