Partial functions, currying and composition

I've been working through Functional Programming in Scala by Chiusano and Bjarnason lately, and it's been a really awesome book. This morning I worked on a few exercises on partial function application, currying and composition that I think demonstrate how powerful Scala can be. I just wanted to paste my solutions here and their translations to Python (3.6), because it's really cool and I'd love feedback on them.

Partial Function Application


First is partial function application. In Scala my solution to this exercise looks as follows.
object HOF_Testing {

  def partial[A, B, C](a: A, f: (A, B) => C): B => C = (b: B) => f(a, b)

  def main(args: Array[String]): Unit = {
    // Test this partial function method on an anonymous function
    val x = 5
    val y = 6

    println("** Partial function application: " + partial[Int, Int, Int](x, (u, v) => u + v)(y))
  }

}

// ** Partial function application: 11
In Python we can achieve the same result by just importing functools.partial, or mimicking the Scala code above in a singleton object. Also, I'd like to point out that all methods are static per Scala's documentation on singleton objects. (In my experience, classes full of nothing but static methods in Python is generally discouraged.)
#! /usr/bin/env python3.6
# -*- coding: utf-8 -*-

""" Get similar functionality in Python with HOF as I did in Scala """

from types import FunctionType as Function
from functools import partial
from typing import Any, Optional


class Singleton(type):
    """ A metaclass to make a singleton object (again, mimicking Scala's `object`) """

    _instance: Optional[type] = None

    def __call__(cls, *args, **kwargs) -> type:
        # If an instance of this class doesn't already exist, create it; otherwise,
        # return that instance
        if not cls._instance:
            cls._instance = cls.__call__(*args, **kwargs)
        else:
            return cls._instance


class HOF_Testing(metaclass=Singleton):
    """ A bunch of HOF methods to compare to my implementations in Scala """

    @staticmethod
    def partial(a: Any, f: Function) -> Function: return lambda b: f(a, b)


if __name__ == '__main__':
    x: int = 5
    y: int = 6

    # Some function that works on integers
    def foo(a: int, b: int) -> int:
        return a + b

    print(f'** functools.partial application: {partial(foo, x)(y)}')
    print(f'** Partial function application : {HOF_Testing.partial(x, foo)(y)}')

# ** functools.partial application: 11
# ** Partial function application : 11

Currying


Next we have currying, which I'd heard of previously by reading a little about Haskell, but never fully understood. In Scala I've added the following method to the singleton above.
...
def curry[A, B, C](f: (A, B) => C): A => (B => C) = (a: A) => partial[A, B, C](a, (a: A, b: B) => f(a, b))
...
And in the main method we can test this as follows.
...
println("** Curried anonymous function  : " + curry[Int, Int, Int]((u, v) => u + v)(x)(y))

// ** Curried anonymous function  : 11
...
In Python we can achieve this same kind of result with nested anonymous lambda functions in the singleton class.
...
@staticmethod
def curry(f: Function) -> Function: return lambda a: lambda b: f(a, b)
...
As before, I can't think of any simple way to use Python's annotations to be as descriptive as Scala's typing system. Testing this method, we have the following output.
...
print(f'** Currying                     : {HOF_Testing.curry(foo)(x)(y)}')

# ** Currying                     : 11
It's still just as straightforward, if not even more simple, but I can't say it's as pleasant to read. One might deduce that this can be extended to a variable number of arguments as well, though I'm not at all sure yet how to write such a method in Scala. In general I believe we have
\begin{align}(A^{N}\rightarrow B)\underset{\text{Uncurry}}{\overset{\text{Curry}}{\require{extpfeil} \Newextarrow{\xrightharpoonup}{1,5}{0x21CC}\xrightharpoonup{}}}(A^{1}\longrightarrow\cdots\longrightarrow A^{N}\longrightarrow B).\end{align} In words, curry converts a function of multiple arguments into a chain of single-argument functions. And uncurry takes a chain of functions and morphs it into a function of several parameters.

Uncurrying


In Scala I've implemented this method as follows (it's a lot simpler than you'd think when first approaching this problem)! At first I was trying to implement it using partial in the opposite way of curry, since they are, in a sense, inverses (perhaps from the perspective of category theory curry would be deemed an isomorphism ?).
...
def uncurry[A, B, C](f: A => (B => C)): (A, B) => C = (a: A, b: B) => f(a)(b)
...
Now in Python, with the help of a lambda, this looks virtually identical.
...
@staticmethod
def uncurry(f: Function) -> Function: return lambda a, b: f(a)(b)
...
I also thought the following test with uncurrying was rather interesting because it resembles reversing a decorator pattern to some extent.
...
def example1(a: int) -> Function:
    def _inner_example1(b: int) -> int:
        return a + b
    return _inner_example1

...
print(f'** Uncurrying                   : {HOF_Testing.uncurry(example1)(x, y)}')

# ** Uncurrying                   : 11 

Uncurrying a curried function and currying an uncurried function

 

In Scala this kind of functionality looks as follows.
...
println("** Uncurrying a curry : " + uncurry[Int, Int, Int](curry((x, y) => x + y))(num1, num2))
println("** Currying an uncurry: " + curry[Int, Int, Int](uncurry(x => y => x + y))(num1)(num2))

// ** Uncurrying a curry : 11
// ** Currying an uncurry: 11
It's actually really interesting seeing them side-by-side and observing the difference in the way we call the function to see its value. Python isn't much different from that above, either.
...
print(f'** Uncurrying a curry           : {HOF_Testing.uncurry(HOF_Testing.curry(foo))(x , y)}')
print(f'** Currying an uncurry          : {HOF_Testing.curry(HOF_Testing.uncurry(example1))(x)(y)}')

# ** Uncurrying a curry           : 11
# ** Currying an uncurry          : 11

Function Composition


In Scala I've written this method as follows.
...
def compose[A, B, C](f: A => B, g: B => C): A => C = (a: A) => g(f(a))
...
It's another beautiful one-liner. In Python, again, it's less descriptive, but very similar.
...
    @staticmethod
    def compose(f: Function, g: Function) -> Function: return lambda a: f(g(a))
...
def one(a: int) -> int:
    return 2 * a

def two(b: int) -> int:
    return b + 1
...
print(f'** Compose functions            : {HOF_Testing.compose(one, two)(y)}')

# ** Compose functions            : 14
Referencing again Peter Thatcher's monads article, it's possible to compose functions using decorators as well.
from functools import wraps
...
    @staticmethod
    def compose_using_decorators(f: Function, g: Function) -> Function:
    
        # A function that makes a function a decorator
        def make_decorate(func) -> Function:
            # Avoid using exceptions if we can, that's what monads are for!
            if 'return' in func.__annotations__.keys():
                ret_type = func.__annotations__['return']
            else:
                ret_type = Any
            @wraps(func)
            def decorator(undecorated) -> Function:
                @wraps(undecorated)
                def decorated(*args, **kwargs) -> ret_type:
                    return func(undecorated(*args, **kwargs))
                return decorated
            return decorator

        # decorate g with f
        return make_decorate(f)(g)
...
    print(f'** Compose with decorators      : {HOF_Testing.compose_using_decorators(one, two)(y)}')

# ** Compose with decorators      : 14
Although I doubt such a complicated solution is ever better than a simple \(\lambda\). Also, it's interesting how this application resembles curry.