Statically-typed functional lists in Python with Mypy

July 21, 2015

Let's implement some functional list functions in Python, using Mypy to annotate and enforce types.

lists.py:

Import some goodies from Mypy's typing module, and Python's functools module:

from typing import TypeVar, Generic, List, Callable
from functools import reduce # type: ignore (see github.com/JukkaL/mypy/issues/500)

Declare a couple of variables:

A = TypeVar('A')
B = TypeVar('B')

Let's get functional:

def fmap(f: Callable[[A], B], xs: List[A]) -> List[B]:
  return list(map(f, xs))

def flatten(xs: List[List[A]]) -> List[A]:
  return reduce(lambda a, b: a + b, xs)

def flatMap(f: Callable[[A], List[B]], xs: List[A]) -> List[B]:
  return flatten(fmap(f, xs))

Type-check it with Mypy:

$ mypy lists.py
$ echo $?
0

No errors -- it compiles! Let's take it for a spin.

demo.py:

from lists import fmap, flatMap

xs = [1, 2, 3]

ys =    fmap(lambda x:  x * 2, xs) # [2, 4, 6)
zs = flatMap(lambda x: [x, x], xs) # [1, 1, 2, 2, 3, 3]

print(ys) # [2, 4, 6]
print(zs) # [1, 1, 2, 2, 3, 3]

Run it with Python:

$ python3 demo.py
[2, 4, 6]
[1, 1, 2, 2, 3, 3]