by signa11 on 10/23/25, 5:42 AM with 151 comments
by JonChesterfield on 10/23/25, 11:28 AM
A combinator is a function that doesn't mutate global state and doesn't close over variables. It's the base case in software. Pass it the same argument, get the same result, doesn't change anything about the rest of the system.
If you combine some of these combinators, you get another combinator - because when you put pure functions together, what you get is a pure function.
These are also the functions that are easy to write in assembly. Or C. Because the don't do very much. So if you write S and K in x64, and then compile common lisp to combinators written in terms of combinators written in terms of S and K, what you've got is common lisp running on those two hand written assembly functions.
That's not a great idea for performance, but if you go with a less spartan set of maybe a few hundred of the most commonly occurring patterns inlined into each other and given names, you've got a viable way "machine" to compile functional programs into.
This looks a bit like a forth that fears mutation. Or a bytecode vm. Or a CPU, where the combinators are called "instructions".
So what combinators are, broadly, is an expression of applied computer science with implementation details ignored as much as possible. That's the sense in which it's simpler than the lambda calculus.
Equally, if you implement the lambda calculus on a handful of combinators, then implement lisp on the lambda calculus, then write stuff in that lisp, you've really cut down how much machine specific work needs to be done at the bottom of the stack.
by tromp on 10/23/25, 8:41 AM
let A = (x) => (y) => (z) => x(z)(y((w) => z))
Just need to combine this a few times. let K = A(A(A))(A(A(A))(A)(A)(A)(A)(A); // (x) => (y) => x
let S = A(A(A(A)(A(A)(A(A)))(A(A(A(A)((A(A)))))))(A)(A); // (x) => (y) => (z) => x(z)(y(z))
> “I would never be caught dead using Lambda calculus. It’s a bloated language.”Actually, combinatory logic is more bloated than lambda calculus, generally needing more bits to express the same program [1]. One can argue that lambda calculus is one of the most concise languages ever [2].
> Dana smirks. “Well, yeah. JavaScript is an eager language. Can’t use the Y combinator.”
Eager languages can be made lazy by wrapping arguments in lambdas with dummy arguments, as done in the Javascript BLC interpreter [3].
[1] https://tromp.github.io/cl/LC.pdf
by egypturnash on 10/23/25, 2:32 PM
“Yes. Do you want the ten-character code golf version, the twelve-line eminently readable version that the junior devs can understand, or the one that’s an excuse to show off some extremely esoteric knowledge and do it in a completely sideways fashion?”
by andersmurphy on 10/23/25, 7:37 AM
https://aphyr.com/posts/353-rewriting-the-technical-intervie...
by RickJWagner on 10/23/25, 12:20 PM
I knew programmers that could write code I wouldn’t understand. Some of them wrote large, valuable systems. I drew the conclusion that some people think in different ways, some had cognitive gifts different from my own. Some were just better at some things.
But the very best programmers wrote code I could follow. It was dirt simple and well documented. Their code made me feel smart as I maintained it. I could understand what the other person was thinking, how the next section would probably go. We were sharing ideas and architectures, but may have never met!
I really liked working with that second type.
by rgovostes on 10/23/25, 7:48 AM
Note that S and K are curried functions which take one argument at a time. Further reading: https://stackoverflow.com/a/36321/
by aleph_minus_one on 10/23/25, 11:09 AM
Programming interviews serve two purposes to find out:
1. Is the candidate knowledgeable in programming?
2. Does the programming style (somewhat) fit the one that is desired by the company?
1 should be clear, and the author clearly passes this part.
For 2: In particular since programming is separated into so many "cultures" of which many of them take deep effort to get more than a superficial knowledge (that's why you talk of "Java shops", "Microsoft/C# shops", ...), in a programming interview, you also want to see whether the candidate will likely be a fit for the prevalent programming culture in the respective company. If you advertise a JavaScript position, it is highly unlikely that if you are that deeply into combinatory logic, you will be a good fit for this position - and thus he would very likely (for good reasons) be rejected if he came up with such a solution.
by vorticalbox on 10/23/25, 4:29 PM
by hanslub42 on 10/23/25, 8:13 PM
by TYPE_FASTER on 10/23/25, 1:18 PM
And I have a new favorite naming convention.
> “Barendregt. Church is too mainstream.” > “It won’t be JavaScript for much longer.”
Douglas Adams teaches SICP.
by dvt on 10/23/25, 12:54 PM
> “Can’t recurse without it.”
Fun fact: there are an infinite number of fixed-point combinators (and therefore infinite ways you can recurse without the Y combinator).
by fschuett on 10/23/25, 12:04 PM
by pbohun on 10/23/25, 2:42 PM
by mrkeen on 10/23/25, 10:49 AM
Does anyone know off the top of their head if the Z combinator would just work here? (Instead of switching to Skoobert)
by underdeserver on 10/23/25, 5:27 PM
Since Astro throws in a lot of inline styles (though it gave up halfway through, which is what prompted me to do this math), the line in the HTML that produces that textarea is 558,580 bytes long (or about 3.3 times as big).
It all adds up to a 700k page.
by mgh95 on 10/23/25, 7:28 AM
> You lean back, exhausted but triumphant.
> Dana is dead.
Thank you for a good laugh.
by pjmlp on 10/23/25, 8:27 AM
Great article by the way.
by tripzilch on 10/24/25, 10:20 AM
That said, I don't think you actually _need_ recursion for a finite problem like FizzBuzz? The Church Numeral for 100 is literally the function `f f f f f f f.. f x` nested 100 times. So that's your loop.
by bryanrasmussen on 10/23/25, 9:40 AM
by andreybaskov on 10/23/25, 5:06 PM
by amelius on 10/23/25, 11:30 AM
https://en.wikipedia.org/wiki/Whitespace_(programming_langua...
by kragen on 10/23/25, 5:31 PM
I hadn't heard of Barendregt numerals before; the reference seems to be to Barendregt, H.P. (1976). A global representation of the recursive functions in the lambda calculus, Theoretical Computer Science 3, pp. 225–242. https://repository.ubn.ru.nl/bitstream/handle/2066/17239/132.... The bit about numerals starts in §4.1 on p. 238 (p. 15/19), so you can just skip there if you don't need an introduction to the λ-calculus and Schönfinkel/Curry combinatory logic.
I wonder if the academic literature would be more enjoyable to read if it were still structured as dialogues, the way it originally was—Hofstadter and Galileo were just calling back to Plato. I think aphyr and Moody fall somewhat short of the standards they set, since the antagonists of their dialogues never raise any real objections, serving only as flimsy, symbolic opposition to the Invincible Hero Mary Sue protagonists, who never make any mistakes or change their minds about anything. As I wrote yesterday in https://news.ycombinator.com/item?id=45669385, narratives are central to how the humans understand anything; even adept, experienced programmers often anthropomorphize parts of their programs, indulging in the "this guy talks to that guy" metaphor that Dijkstra so famously deplored, on the perhaps reasonable grounds that it led to illogical thinking.
by latexr on 10/23/25, 9:23 AM
> It is also extremely difficult to understand.
But nowhere do I see a reason why we should learn the thing. Is It useful in any way? Is it just a curiosity? Does it develop your thinking? Any reason is fine, but if you don’t give one we’re just left looking at something which looks both complex and useless, so why would we learn further?
To really drive the point home, I have no doubt this would be fun to learn and even useful for a certain kind of people. But because you don’t say, we don’t know if we fit the bill.
by 0xCE0 on 10/24/25, 10:16 AM
https://writings.stephenwolfram.com/2020/12/combinators-a-ce...
by abstractspoon on 10/23/25, 6:51 AM
by mikewarot on 10/23/25, 5:21 PM
by TedHerman on 10/23/25, 11:44 AM
by JadeNB on 10/23/25, 9:42 AM
by gradschool on 10/23/25, 3:16 PM
foo(x) = if (x == K) return S else return K
by andyferris on 10/23/25, 1:09 PM
Uncaught RangeError: Maximum call stack size exceeded
at REPL2:1:16
at REPL1:1:30
at REPL1:1:34
at REPL1:1:30
at REPL1:1:30
at REPL1:1:30
at REPL1:1:35
at REPL1:1:34
at REPL1:1:34by tonyedgecombe on 10/23/25, 9:41 AM
by beepbooptheory on 10/23/25, 6:18 PM
Was absolutely shocked for second seeing Žižek on the hn frontpage.
by xplt on 10/24/25, 9:14 PM
FizzBuzz in an on-site interview on your personal laptop?
by tdeck on 10/24/25, 6:03 AM
by 334f905d22bc19 on 10/23/25, 7:43 AM
by jackdoe on 10/23/25, 8:05 AM
brilliant work!
by TZubiri on 10/24/25, 3:16 AM
by wrs on 10/23/25, 3:50 PM
by senfiaj on 10/23/25, 9:15 PM
by dc10tonite on 10/24/25, 2:49 AM
by NoSalt on 10/23/25, 3:02 PM
:-(
by xcf_seetan on 10/23/25, 9:53 AM
by drob518 on 10/23/25, 5:06 PM
by the_af on 10/23/25, 2:23 PM
by davedx on 10/23/25, 12:29 PM
by singpolyma3 on 10/23/25, 5:38 PM
by temperceve on 10/23/25, 12:24 PM
haha
by 1dolinski on 10/23/25, 4:40 PM
make fizzbuzz up to 20 only starting with these combinatory functions
let S = (x) => (y) => (z) => x(z)(y(z)); let K = (x) => (y) => x;
10 seconds later https://gist.github.com/1dolinski/93c2e193e5bc6fad9acfc33d71...
by 01HNNWZ0MV43FF on 10/23/25, 4:46 PM
by alienbaby on 10/23/25, 2:26 PM
We have a guy who joined recently who constantly tries to be as clever as possible when writing his code. He ignores established patterns and conventions because he knows better. He does some cool stuff. Really cool stuff.
He's so far bounced thorugh 3 different teams, I don't think he'll be with us long.
by caporaltito on 10/23/25, 9:42 AM
by jaeyson on 10/23/25, 7:49 AM
by p0w3n3d on 10/23/25, 2:43 PM
by Atomic_Torrfisk on 10/23/25, 1:27 PM