While I agree with the general approach, I’m not convinced the specific solution is superior. It’s unclear what ignore actually ignores (turns out an exception?). And the behaviour of decorator was non-obvious to me. But maybe that’s just a Python thing.
I think what many people either don’t realize or disagree with is: turing completeness is a curse. The problem with loops (recursion included) is that they can do anything. You can’t just eyeball a piece of loop code and understand what it fundamentally does. The combinators provide a loop-DSL which limit what they do. This means when you see map you know the semantics of that loop. When you see for you know very little about what it does.
This means when you see map you know the semantics of that loop. When you see for you know very little about what it does.
Rather than rely on programming by name, this goes a lot further if you have parametricity.
We know what
map :: (a -> b) -> [a] -> [b]
fmap :: Functor f => (a -> b) -> f a -> f b
do because we have pervasive polymorphism by default. This works for user defined functions as well.
For practical uses naming is enough.