CodeWars: Calculating With Functions

The Problem

Write functions that calculate integer arithmetic. For example.

seven(times(five()))

Should return thirty-five. Every number has a function and there are four operation-functions:

  • plus
  • minus
  • times
  • divided_by

All operations should return integers, not floats.

The Solution

# python
from functools import partial

def digit(operation=None, integer=None):
    """A base function to define a digit

    Args:
     operation: a function that expects an integer argument when called
     integer: an integer to return if no operation is passed in
    """
    if operation is not None:
        return operation(integer)
    return integer

# the digits
zero = partial(digit, integer=0)
one = partial(digit, integer=1)
two = partial(digit, integer=2)
three = partial(digit, integer=3)
four = partial(digit, integer=4)
five = partial(digit, integer=5)
six = partial(digit, integer=6)
seven = partial(digit, integer=7)
eight = partial(digit, integer=8)
nine = partial(digit, integer=9)

# the operations
def plus(right: int):
    return lambda left: left + right

def minus(right: int):
    return lambda left: left - right

def times(right: int):
    return lambda left: left * right

def divided_by(right):
    return lambda left: left // right

The Tests

expect(seven(times(five()))).to(equal(35))
expect(four(plus(nine()))).to(equal(13))
expect(eight(minus(three()))).to(equal(5))
expect(six(divided_by(two()))).to(equal(3))

Alternatives

There are several variations on the theme. One that I thought was similar in spirit to what I did but better was this one. Instead of separate operation and integer they use a default function that only returns what gets passed to it. So the definitions look like this.

def identity(integer: int) -> int:
    return integer

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)

expect(seven(times(five()))).to(equal(35))
expect(four(plus(nine()))).to(equal(13))
expect(eight(minus(three()))).to(equal(5))
expect(six(divided_by(two()))).to(equal(3))

A Hybrid

To add a little of what the other solution is doing…

# python
from functools import partial

def identity(integer: int) -> int:
    """A pass-through function

    Args:
     integer: a digit input

    Returns:
     the integer given
    """
    return integer

def digit(operation=identity, integer=None):
    """A base function to define a digit

    Args:
     operation: a function that expects an integer argument when called
     integer: an integer to return if no operation is passed in
    """
    return operation(integer)

# the digits
zero = partial(digit, integer=0)
one = partial(digit, integer=1)
two = partial(digit, integer=2)
three = partial(digit, integer=3)
four = partial(digit, integer=4)
five = partial(digit, integer=5)
six = partial(digit, integer=6)
seven = partial(digit, integer=7)
eight = partial(digit, integer=8)
nine = partial(digit, integer=9)

# the operations
# this is a style some people used. I'm not sure I like it.
plus = lambda right: lambda left: left + right
minus = lambda right: lambda left: left - right

# alternatively you could just do this
def times(right: int): return lambda left: left * right
def divided_by(right): return lambda left: left // right

expect(seven(times(five()))).to(equal(35))
expect(four(plus(nine()))).to(equal(13))
expect(eight(minus(three()))).to(equal(5))
expect(six(divided_by(two()))).to(equal(3))