The Challenge

I came across an interesting kata on Codewars.

Example 1. Calculating with Functions Kata

This time we want to write calculations using functions and get the results. Let’s have a look at some examples:

seven(times(five())) # must return 35
four(plus(nine())) # must return 13
eight(minus(three())) # must return 5
six(divided_by(two())) # must return 3
Requirements
  • There must be a function for each number from 0 ("zero") to 9 ("nine")
  • There must be a function for each of the following mathematical operations: plus, minus, times, dividedBy (divided_by in Ruby and Python)
  • Each calculation consist of exactly one operation and two numbers
  • The most outer function represents the left operand, the most inner function represents the right operand
  • Divison should be integer division. For example, this should return 2, not 2.666666…​:
eight(divided_by(three()))

This task should not be any problem for a seasoned functional programmer. Rookies however might shed some sweat while working out the solution. The key is in realization that a function call does not have to return just a number/string/object... but it can return a function as well.
Plus, if you were not familiar with lambdas in Python, now, after finising the kata, you are.

Example 2. Lambda Expression in Python

Syntax: lambda arguments: expression

myVar = lambda a: a + 2
res = myVar(8) #res = 10

One small bummer here: Python is not able to create a multiline lambda without some tinkering around. You’ll have to use a named function for more sophisticated calculations

def do_magic(x):
    y = x + 5
    y = y * x
    return y

myVar = do_magic
res = myVar(1) # res = 6
Warning:

Spoiler alert: If you would like to figure out the solution yourself, stop right here.

The solution

This is the simplest solution. Of course, the code is not ideal, you have a function for each number. There is a more universal approach but that is out of scope of this post.

def identity(x): return x

def zero(f=identity): return f(0)
def one(f=identity): return f(1)
def two(f=identity): return f(2)
def three(f=identity): return f(3)
def four(f=identity): return f(4)
def five(f=identity): return f(5)
def six(f=identity): return f(6)
def seven(f=identity): return f(7)
def eight(f=identity): return f(8)
def nine(f=identity): return f(9)

def plus(y): return lambda x: x+y
def minus(y): return lambda x: x-y
def times(y): return lambda  x: x*y
def divided_by(y): return lambda  x: x/y

From the solutions, it is also possible to simplify the definition of the 'numbers'

id_ = lambda x: x
number = lambda x: lambda f=id_: f(x)
zero, one, two, three, four, five, six, seven, eight, nine = map(number, range(10))

How it works

res = seven(times(five())) #35
  1. five() returns
    f(5) = identity(5) = 5
  2. times(5) returns a function
    x: x*5
  3. seven(x: x*5) does
    f(7) = 7*5 = 35

A simple yet elegant reminder of higher order functions.