|
| 1 | +#! /usr/bin/python |
| 2 | + |
| 3 | +# In Python, and other languages, functions are "first class citizens": |
| 4 | +# They are objects which can be treated as you would a variable or any other object |
| 5 | +# (passed as argument to another function, returned by a function, and so on). |
| 6 | +# |
| 7 | +# A function which takes or returns a function is called a functional, or higher-order function |
| 8 | +# (e.g. an integral takes a function as an argument). |
| 9 | +# |
| 10 | +# Use of these properties is called the functional programming paradigm. |
| 11 | +# |
| 12 | +# The origin for (and simplest instance of) a functional object is the labmda expression. |
| 13 | + |
| 14 | +#http://docs.python.org/release/2.7.6/tutorial/ |
| 15 | + |
| 16 | +#============================================== |
| 17 | + |
| 18 | +# 4.7.5 Lambda expressions (c.f. C function pointers) |
| 19 | +# "Lambda expression" here is a small, anonymous function; |
| 20 | +# used whenever a function is required to be represented as an object. |
| 21 | +# Syntactically restricted to a single expression... |
| 22 | + |
| 23 | +# Lambda expression returning unevaluated function object |
| 24 | +add = lambda a,b: a+b |
| 25 | +print add(1,2) # evaluate function object |
| 26 | +argsList=[2,3] |
| 27 | +print apply(add,argsList) # using non-essential 'apply()' function |
| 28 | + |
| 29 | +# Lambda expresssion referrencing value from containing scope (like nested function definitions) |
| 30 | +def make_incrementor(n): |
| 31 | + return lambda x: x+n # given parameter 'n' and taking argument 'x', return the value 'x+n' |
| 32 | +f=make_incrementor(42) # 'f' is now a function object with n=42 |
| 33 | +print "f(0)= ", f(0) # print the evaluated function for x=0 |
| 34 | +print "f(1)= ", f(1) # print the evaluated function for x=1 |
| 35 | + |
| 36 | +# Sort list according to a key, where the key is a lambda expression |
| 37 | +pairs=[(1,'one'),(2,'two'),(3,'three'),(4,'four')] |
| 38 | +print "Before sort: ", pairs |
| 39 | +pairKey=lambda pair: pair[1] # Lambda expression which, given an object 'pair', returns the [1] element (i.e. the second elemnt in the tuple) |
| 40 | +pairs.sort(key=pairKey) # Sort pairs according to the name of the number (i.e. alphabetically) |
| 41 | +print "After sort: ", pairs |
| 42 | + |
| 43 | +#============================================== |
| 44 | +print |
| 45 | + |
| 46 | +# 5.1.3 Functional programming (functional = higher-order function) |
| 47 | + |
| 48 | +# Filter (aka C++ <algorithm> remove_copy_if() , etc.) |
| 49 | + |
| 50 | +# Example: filter out Capital letters, punctuation marks, and spaces |
| 51 | +stringEx="Hello World!" |
| 52 | +print stringEx |
| 53 | +def someBoolFunction(x): |
| 54 | + return (ord(x) > 97) # is the ASCII value of the character x greater than 97? |
| 55 | +print filter(someBoolFunction,stringEx) # returns only string, tuple or list (depending on input) |
| 56 | + |
| 57 | +# Example: compute a sequence of numbers not divisible by 2 or 3 |
| 58 | +def notDiv2or3(x): |
| 59 | + return (0 != x % 2) and (0 != x % 3) |
| 60 | +print filter(notDiv2or3, range(2,25)) # recall that range is inclusive of 'from' argument and exclusive of 'to' argument |
| 61 | + |
| 62 | +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 63 | +print |
| 64 | + |
| 65 | +# Map (aka C++ <algorithm> transform() |
| 66 | + |
| 67 | +# Example: "do for each" return cube |
| 68 | +def cube(x): |
| 69 | + return x*x*x |
| 70 | +print map(cube, range(1,10)) |
| 71 | + |
| 72 | +# Example: map multiple sequences (e.g. lists) |
| 73 | +def add2(a,b): |
| 74 | +## if int(a) and int(b): return a+b |
| 75 | +## elif int(a): return a # i.e. ! int(b) |
| 76 | +## else: return b # int(b) but ! int(a) |
| 77 | +## if (type(a) is IntType) and (type(b) is IntType): return a+b # requires 'from types import *' |
| 78 | + return a+b if (type(a)== type(b)) else 'undefined' |
| 79 | +seq1=range(0,8) |
| 80 | +seq2=range(-6,4) # note that len(seq2) > len(seq1) |
| 81 | +print map(add2,seq1,seq2) |
| 82 | + |
| 83 | +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 84 | +print |
| 85 | + |
| 86 | +# Reduce (aka Fold, C++ <numeric> accumulate() |
| 87 | +# see also python 3 'compose' and Haskell 'scan' |
| 88 | + |
| 89 | +# serial composition of binary function (takes two arguments at a time) from left to right: |
| 90 | + |
| 91 | +# leftFold(f;a,b,c,d) = f( f( f(a,b) ,c) ,d) |
| 92 | +print "((2/3)/4)/5 = 1/30", |
| 93 | +def div(x,y): return float(x)/float(y) |
| 94 | +l=range(2,6) |
| 95 | +print reduce(div,l) |
| 96 | + |
| 97 | +# can take initial value argument: |
| 98 | +print "((((1)/2)/3)/4)/5 = 1/120", |
| 99 | +initVal=1 |
| 100 | +print reduce(div,l,initVal) |
| 101 | + |
| 102 | +# rightFold(f;a,b,c,d) = f(a , f(b, f(c,d) ) ) |
| 103 | +print "2/(3/(4/5)) = 8/15", |
| 104 | +def vid(x,y): |
| 105 | + return div(y,x) # reverse function object |
| 106 | +lRev=reversed(range(2,6)) # reverse argument list (compose d,c, then b, then a ...) |
| 107 | +print reduce(vid,lRev) |
| 108 | + |
| 109 | +# Example: sum numbers from 1 through 10 (inclusive) |
| 110 | +def add(x,y): return x+y |
| 111 | +print reduce(add,range(1,11)) |
| 112 | + |
| 113 | + |
| 114 | +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 115 | +print |
| 116 | + |
| 117 | +# Example: Parralelization of search for all multiples of 'q' in the range [a:b] |
| 118 | +# 1) Split range [a:b] to n sub-ranges. |
| 119 | +# 2) MAP multiple-finding function to each sub-range, and execute in parallel. |
| 120 | +# 3) REDUCE result lists back to a single list. |
| 121 | + |
| 122 | + |
| 123 | +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 124 | +print |
| 125 | + |
| 126 | +# Creating a list using functional programming |
| 127 | +# specifically, using map()... |
| 128 | + |
| 129 | +squaresLambda=map(lambda x: x**2, range(3)) |
| 130 | +print squaresLambda |
| 131 | + |
| 132 | + |
| 133 | +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 134 | +print |
| 135 | +# 5.1.4 listcomp: List comprehension |
| 136 | +# Concise way of creating a list in which each element is the result of some opperation, applied to each member of another sequence or iterable. |
| 137 | + |
| 138 | +squaresExplicit=[] # create empty list |
| 139 | +for x in range(3): |
| 140 | + squaresExplicit.append(x**2) |
| 141 | +print squaresExplicit |
| 142 | + |
| 143 | +squaresListcomp=[x**2 for x in range(3)] #concise expression, using list compehension |
| 144 | +print squaresListcomp |
| 145 | + |
| 146 | + |
| 147 | +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 148 | +print |
| 149 | +# More complex list comprehension (more than one 'for' and additional 'if' clauses) |
| 150 | +# For example, the sequence of subsequences of non-negative integers, |
| 151 | +# such that each subsequence is shorter than 6 integers long (including zero) |
| 152 | +seqOfsubSeq=[x for y in range(10) for x in range(y) if y<6] |
| 153 | +print seqOfsubSeq |
0 commit comments