Next Chapter: Finite State Machine in Python

## Currying

### General Idea

In mathematics and computer science, currying is the technique of breaking down the evaluation of a function that takes multiple arguments into evaluating a sequence of single-argument functions.f Currying is also used in theoretical computer science, because it is often easier to transform multiple argument models into single argument models.

### Composition of Functions

We define the composition h of two function f and g

$$h(x) = g(f(x))$$

in the following Python example.

The composition of two functions is a chaining process in which the output of the inner function becomes the input of the outer function.

def compose(g, f): def h(x): return g(f(x)) return h

We will use our compose function in the next example. Let's assume, we have a thermometer, which is not working accurate. The correct temperature can be calculated by applying the function *readjust* to the temperature values. Let us further assume that we have to convert our temperature values into degrees fahrenheit. We can do this by applying *compose* to both functions:

def celsius2fahrenheit(t): return 1.8 * t + 32 def readjust(t): return 0.9 * t - 0.5 convert = compose(readjust, celsius2fahrenheit) convert(10), celsius2fahrenheit(10)The above Python code returned the following output:

(44.5, 50.0)

The composition of two functions is generally not commutative, i.e. compose(celsius2fahrenheit, readjust) is different from compose(readjust, celsius2fahrenheit)

convert2 = compose(celsius2fahrenheit, readjust) convert2(10), celsius2fahrenheit(10)The above Python code returned the following output:

(47.3, 50.0)

*convert2* is not a solution to our problem, because it is not readjusting the original temeratures of our thermometre but the transformed Fahrenheit values!

## Example Currency Conversion

In our chapter on Magic Functions we had an excercise on currency conversion.

## "compose" with Arbitrary Arguments

The function *compose* which we have just defined can only copy with single-argument functions. We can generalize our function *compose* so that it can cope with all possible functions.

def compose(g, f): def h(*args, **kwargs): return g(f(*args, **kwargs)) return h

Example using a function with two parmameters.

In [ ]:def BMI(weight, height): return weight / height**2 def evaluate_BMI(bmi): if bmi < 15: return "Very severely underweight" elif bmi < 16: return "Severely underweight" elif bmi < 18.5: return "Underweight" elif bmi < 25: return "Normal (healthy weight)" elif bmi < 30: return "Overweight" elif bmi < 35: return "Obese Class I (Moderately obese)" elif bmi < 40: return "Obese Class II (Severely obese)" else: return "Obese Class III (Very severely obese)" f = compose(evaluate_BMI, BMI) weight = 1 while weight > 0: weight = float(input("weight (kg) ")) height = float(input("height (m) ")) print(f(weight, height))

weight (kg) 73 height (m) 1.76 Normal (healthy weight) weight (kg) 75 height (m) 1.76 Normal (healthy weight)

def arimean(*args): return sum(args) / len(args) def curry(func): f_args = [] f_kwargs = {} def f(*args, **kwargs): nonlocal f_args, f_kwargs if args or kwargs: f_args += args f_kwargs.update(kwargs) return f else: return func(*f_args, *f_kwargs) return f s = curry(arimean) s(2)(5)(9)(4, 5) s(5, 9) print(s()) s2 = curry(arimean) s2(2)(500)(9)(4, 5) s2(5, 9) s2()

5.571428571428571The previous Python code returned the following output:

76.28571428571429

Next Chapter: Finite State Machine in Python