The long way through Software Craftsmanship

The Threading Macro (clojure) equivalent in Python

Jul 22, 2023 - 2 minute read - Comments - equivalencethreading-macroclojurelispmacropythonlanguagelanguage-equivalence

Introduction

In any programming language, it is common to compose functions by pipelining functions: h = g ∘ f such that h(x) = g(f(x)).

The function f is applied first, then g, then the following. 1

For me, it would be more comfortable and easy to understand to write it f COMPOSE_THEN g, indicating that this function composition is not the usual, but a different operation.

Introduction in Clojure

This function composition can be written in Clojure by pipelining or chaining functions:

(defn calculate []
   (reduce + (map #(* % %) (filter odd? (range 10)))))

Fig 1: Example taken from Clojure’s threading macros. Notice the (range 10) is written at the right-most, while the functions are at the left of it.

The threading macros are also a magnificent way to chain or pipeline operations: take a value and put it through the following functions:

(defn calculate* []
   (->> (range 10)
        (filter odd?)
        (map #(* % %))
        (reduce + )))

Fig 2: when using threading macros. Notice the (range 10) is written at the beginning, while the functions are to the right of it. This is a more natural way of reading code (left to right).

Python

In python, I haven’t found any equivalent 2 to these threading macros, but it is possible to create an equivalent 3:

def chain(arg: object, *funcs: Any) -> object:
    return reduce(lambda r, f: f(r), funcs, arg)

and to use it:

chain(range(10),
      lambda ele: filter(lambda x: x % 2 == 1, ele),
      lambda ele: map(lambda x: x * x, ele),
      sum
      )

The upside is that you can now chain functions, while the parameter is at the beginning.

The obvious downside is you need to create lambda functions for each of the functions.


  1. The notation g ∘ f is read as “g of f “, “g after f " (…). From wikipedia: Function Composition ↩︎

  2. In the python 3 SDK or the Standard Library. There might be alternatives, but I haven’t researched them: funcy, funcoperators, or toolz. ↩︎

  3. This Stack Overflow thread is related to function composition ↩︎