Why Functional Simplicity Makes AI Shine - HuMpY tExT Edition
Friday, October 10, 2025We’ve been talking about writing AI-friendly code, and one of the easiest ways to get there is through a lightweight functional approach.
AI tools like Cursor (and even ChatGPT) thrive when the code they see predictable, testable, and free of hidden side effects.
That doesn’t mean turning our apps into a math experiment — it means writing small, pure functions that can be composed together and tested in isolation.
To show what that looks like in its simplest form, here’s a tiny (and relatively useless) example I built close to 10 years ago — a little snippet that converts text into alternating upper/lower case: HuMpY tExT.
👉 CodePen: https://codepen.io/JDHorn/pen/MWWoPJK?editors=0010
🧩 The Full Code
1const text = "Enter some text";
2
3// arrow function version
4const pipe_ = (...fns) => (accumulator) =>
5 fns.reduce((fn, reducer) => reducer(fn), accumulator);
6
7// classic function
8function pipe(...fns) {
9 return function (result) {
10 fns.reduce(function (val, fn) {
11 return fn(val);
12 }, result);
13 };
14}
15
16const splitChars = (dirty) => [...dirty];
17const joinResult = (arr) => arr.join("");
18
19const modArray = (arr) => {
20 const result = [];
21 const toggler = function (toggle = false) {
22 return function () {
23 return (toggle = !toggle);
24 };
25 };
26
27 const toggle = toggler();
28 const isAlpha = (dirty) => !!dirty.match(/[a-zA-Z]/);
29 const pushToResult = (dirty) => result.push(dirty);
30
31 const switchCase = (dirty) =>
32 isAlpha(dirty)
33 ? toggle()
34 ? dirty.toUpperCase()
35 : dirty.toLowerCase()
36 : dirty;
37
38 const convertThenPush = pipe(switchCase, pushToResult);
39 arr.forEach(convertThenPush);
40
41 return result;
42};
43
44const updateOutput = (entry = text) => (target.innerText = entry);
45
46const convertArrayToHumpyCaseAndPrint = pipe(
47 splitChars,
48 modArray,
49 joinResult,
50 updateOutput
51);
52
53const el = document.getElementById("entry");
54const target = document.getElementById("target");
55
56el.addEventListener("focus", () => el.select());
57target.addEventListener("focus", () =>
58 window.getSelection().selectAllChildren(target)
59);
60
61const modifyText = (ev) => convertArrayToHumpyCaseAndPrint(ev.target.value);
62el.addEventListener("keyup", modifyText, false);
63
64updateOutput();🤔 Why This Matters for AI-Driven Development
Predictability → Better AI suggestions
Pure functions behave deterministically, so Cursor can safely reason about them and build on top of them.
Isolation → Safer AI refactors
When side effects live at the edges, the AI can’t accidentally break something hidden.
Clarity → Smarter completions
Each step has a single responsibility, making the intent easy for both humans *and* AI to follow.
🪄 Functional at a Glance
Each small function does one thing:
splitChars→ break input into datamodArray→ transform that datajoinResult→ reassemble itupdateOutput→ perform the one side effect (DOM update)
Everything up to updateOutput is pure - no external dependencies, no mutation, fully testable.
💡 Keep It Stupid Simple (KISS-FP)
We’re not introducing monads or heavy FP libraries — just encouraging a small habit:
Write pure, composable functions.
Chain them together.
Keep side effects at the edges.
It keeps our code AI-ready, human-readable, and ridiculously easy to test 💪

