bnjmn.

functional programming in python

2025-01-22

My experience with functional programming has been rocky, to say the least.

I mean, it’s a hard thing. I’m not the most math-inclined person, so my eyes start to glaze over when I see things like “abstract algebra”, “category theory”, “functors” and what-have-you. Still, I did commit myself to some of it, for a season. I tried rescript, then purescript, and none of it was really “clicking” - and everyone says “just learn haskell bruh” - so I put myself through the painful process of reading HPFFP (some have likened it to self-flagellation - I tend to agree). I got halfway through, read about monad transformers somewhere, and decided the juice just wasn’t worth the squeeze.

I feel like you have to get yourself to a certain headspace to do functional programming. Some of it just sounds like copium, man:

  • “In Haskell, every function has to return something - so we return a unit, problem solved.”
  • “Functional programming is pure! As long as you take in a world, and return a new world!”

To be clear, I think functional programming can be useful. I just find pure FP terribly impractical and unproductive. “Functional-lite”, I can get behind.

/rant

Anyway, today I came across a dialect of Python called coconut and played with it a little. I know you’re not supposed to do things like this in Python (I know the creator is anti-FP - or at least anti-TIMTOWTDI), but here’s some code:

"""
  files end in .coco
  you can run a .coco file with `coconut -r main.coco`
"""

print("hi from coco")

l = x -> x + 1 # concise lambdas

def first([]): return [] # pattern matching
def first([head] + tl):
  """
    Usually we'd write something like:
    ```
    hd, *_ = list
    ```
    But I don't know if that's allowed in Coconut. I couldn't get it to compile :|
  """
  return head

exclaim = map$((x) => x + "!", ?) # fat arrows, partial application

# pipelines

["We have fat arrow"] |> exclaim |> list |> first |> print # "We have fat arrow!"

# more partials

def greet(greeting, person):
  return f"{greeting}, {person}"

greet_bob_with = greet$(?, "bob")
greet_bob_with("hi") |> print # "hi, bob"
greet_bob_with("YO") |> print # "YO, bob"

def url_builder(base, endpoint):
  return f"{base}/{endpoint}"

build_example = url_builder$("www.todos.com", ?)
todos = build_example("api/todos") |> print # prints what you'd expect
projects = build_example("api/projects") |> print

"""Reduction? Operators?"""

\sum = reduce$(+) # need this because it shadows python's built-in sum
range(1, 6) |> \sum |> print
mult = reduce$(*)
range(1, 6) |> mult |> print

# lazy lists

xs = (| f(a), f(b), f(c) |)
a = 1
b = 300
c = 25
# f = (x) => str(x)
f = str # pt-free
xs |> print # reiterable(<itertools._tee object at 0x782e2347fe00>)
xs |> list |> "".join |> print # force evaluation => 130025

So, yeah. Just wanted to share. It’s quite fun, actually.