Skip to content

Instantly share code, notes, and snippets.

@internetimagery
Last active June 28, 2026 11:01
Show Gist options
  • Select an option

  • Save internetimagery/d8e92ad5270920d0e38525595de1d684 to your computer and use it in GitHub Desktop.

Select an option

Save internetimagery/d8e92ad5270920d0e38525595de1d684 to your computer and use it in GitHub Desktop.
Messing around with mapn codegen
from functools import partial, reduce
class M:
def __init__(self, val):
self.val=val
def map(self, func):
return M(func(self.val))
def bind(self, func):
return M(func(self.val).val)
def __repr__(self):
return f"<M {self.val} >"
def result(v1, v2, v3):
return f"{v1}-{v2}-{v3}"
one = M("one")
two = M("two")
three = M("three")
_code_cache = {}
def mapN(func, *monads):
num_monads = len(monads)
code = _code_cache.get(num_monads)
if code is None:
vals = [f"v{i}" for i in range(num_monads)]
lambdas = f"{' '*(num_monads+1)}return tgt({','.join(vals)})"
for i in reversed(range(num_monads)):
args = [vals[i]]
args.extend(f"{arg}={arg}" for arg in vals[:i])
indent = " " * (i+1)
method = 'map' if i+1 == num_monads else 'bind'
lambdas = f"{indent}def f{i}({','.join(args)},tgt=tgt,mns=mns):\n{lambdas}\n{indent}return mns[{i}].{method}(f{i})"
lambdas = f"def runner(tgt,mns):\n{lambdas}"
ns = {"__builtins__": None}
exec(lambdas, ns)
# print(lambdas)
code = _code_cache[num_monads] = ns["runner"]
return code(func, monads)
def first():
return one.bind(lambda v1: two.bind(lambda v2: three.map(lambda v3: result(v1, v2, v3))))
baseline = first()
assert baseline.val == "one-two-three"
# 1.11 µs ± 19.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
# Intuitiion... functions are replaced by values at each step. Same number of args the whole way.
def second():
ff = lambda f1, f2, f3: f1(lambda v1, f2=f2, f3=f3: f2(lambda v2, v1=v1, f3=f3: f3(lambda v3, v2=v2, v1=v1: result(v1, v2, v3))))
return ff(one.bind, two.bind, three.map)
v = second()
assert v.val == "one-two-three"
# 1.35 µs ± 64.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
cache = {
3: eval("lambda f1, f2, f3: f1(lambda v1, f2=f2, f3=f3: f2(lambda v2, v1=v1, f3=f3: f3(lambda v3, v2=v2, v1=v1: result(v1, v2, v3))))"),
4: eval("lambda f1, f2, f3: f1(lambda v1: f2(lambda v2: f3(lambda v3: result(v1, v2, v3))))"),
}
def second_cached_variant(n):
return cache[n](one.bind, two.bind, three.map)
assert second_cached_variant(3).val == "one-two-three"
assert second_cached_variant(4).val == "one-two-three"
# 1.23 µs ± 44.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
# Intuitiion. Curried functon can be mapped and bind-ed over
def third():
ff = partial(partial, partial(partial, partial(result)))
return one.map(ff).bind(two.map).bind(three.map)
v = third()
assert v.val == "one-two-three"
# 1.71 µs ± 31.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
def fourth():
return mapN(result, one, two, three)
v = fourth()
assert v.val == "one-two-three"
# 1.31 µs ± 31.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment