Picture Me Coding
Picture Me Coding is a music podcast about software. Each week your hosts Erik Aker and Mike Mull take on topics in the software world and they are sometimes joined by guests from other fields who arrive with their own burning questions about technology.
Produced by Neiko Will.
Logo and artwork by Jon Whitmire - https://www.whitmirejon.com/
Reach out to us here: podcast@picturemecoding.com
Picture Me Coding
Hidden Vibrations of the Universe: Compositionality
This week we take on the subject of compositionality, an ultra-abstract concept that might just underlie all the programming things we do.
Does this idea really inform our work? Do we need category theory to talk about and understand it? Are we required to care?
Here are some references:
- The Composable Codex | Voltron Data
- On the Criteria To Be Used in Decomposing Systems into Modules (1972)
- Composing Software: The Book - by Eric Elliott
- "Category: The Essence of Composition" from Bartosz Milewski's Programming Cafe
- Seven Sketches in Compositionality: An Invitation to Applied Category Theory
- Erik's `compose` implementation in Python.
[MUSIC] >> Hello, welcome to Picture Me Coding with your host, Erik Aker and Mike Mull.
My name is Erik.
Hi, Mike.
How are you doing?
>> Hey there.
Doing pretty well.
How are you?
>> I'm doing pretty well.
I've been listening to this record by a guy named Eric, the architect.
He shares my first name, but he spells it with a C.
A record's called I've Never Been Here Before.
I really like it.
It's a hip-hop record.
It's got this quality that I keep hearing my ears attracted to in contemporary music where it starts sounding familiar and then things adapt and change and develop.
I don't know why, but there are a lot of people writing songs where they start out one way and they transmute into some other thing partway through.
I'm into that lately.
Anyway, it's relaxing, but there's some pretty smart lyricism in it.
I like it.
I've never been here before.
>> I like it too.
I listened to it a couple of times after you pointed me at it.
I do wonder how much of this album, how much of the fact that you like this album is because you are named Eric and you are a software architect.
>> That has nothing to do with that.
I actually have never called myself a software architect before.
This guy is more of an architect than I am, I would say.
>> Other people call you an architect though.
>> I don't know what to say about those other people.
How about you?
What are you listening to?
>> Slightly strange choice this week.
For some reason, I've gone back to listen to an album from 2012.
It's by the band Pinback.
Pinback is a San Diego band.
>> Nothing strange about listening to Pinback here at San Diego.
>> I know that one of the members is from Three Mile Pilot, which I know you're a fan of.
>> Zach, yep.
>> I was a big fan of the band.
They haven't really made anything in the last decade that I'm aware of.
This album is from 2012.
They had come off a couple of really critically acclaimed albums.
They did Autumn of the Seraphs and Summer in Abaddon.
We're kind of like indie rock darlings for a while there.
Then this album came out in 2012.
Everybody was kind of like, "Eh, whatever."
I was kind of surprised because I really like this album.
I've been listening to it again.
I think it has probably my favorite Pinback song on it, which is called True North.
I don't really understand why people don't love this one like they love some of the other ones.
But they're a very distinctive band.
Every time you hear a Pinback song, it's kind of like, "Oh, this must be Pinback."
Probably the only band I can really think to even compare them to is maybe Death Cab.
>> That's an interesting comparison.
For me, they're part of this family tree of bands from Encinitas.
>> They were a pretty big band probably from the 20 Aughts.
>> I mean, and that way, the deck has a blank bass.
You don't really ever hear that.
He's playing chords on the bass.
That's not common.
>> Two other interesting things about this album and Pinback in general.
One is that the album is named Information Retrieved.
It's from 2012, so it's a very good computer nerd title.
>> Oh, that's a good point.
I didn't think about that.
>> The other interesting, well, probably not that interesting, but the other factoid about Pinback is that Summer in Abaddon is the last album I bought on physical media.
>> Oh, wow.
>> I can't remember what year that was, maybe 2007 or something like that.
A CD store opened up in part of town that I live in.
It was already at the point in history where CDs were kind of going the way of cassette tapes and vinyl.
And I just, to be honest, felt a little bad for them.
So I went in and bought a few CDs, one of which was Summer in Abaddon.
Anyway, I would give it a listen.
I think it's a much better album than, I think it's underappreciated, let's just say.
>> Information Retrieved Pinback.
I'll have to go back and listen to it.
I know I've heard it.
I saw them play a couple times.
You ever see them play?
>> I have not, no.
>> One of my favorite shows I've ever seen, actually, and this s a little bit unfair because this is more of a, it's the adjacent band, but Black Heart Procession.
First Black Heart Procession album comes out sometime in the 90s, probably '96, '97.
I saw them at the Che Cafe.
There were fewer than 2,000 people there.
All the lights were off except for this blue lamp that was a fish holding up a blue light bulb.
And they were playing the saw.
It was one of the craziest shows ever.
It was amazing.
I'm not in Black Heart Procession.
>> At the Che.
It's been super loud.
>> It was cool.
That's Paul from Through My Pilot and Black Heart Procession.
Of course, Zach was in Through My Pilot.
Anyway, sorry, a little bit off the rail, sir.
Tell me about the topic you wanted to cover this week.
>> So this word popped into my head because of some things I've been reading and the topic is composition, particularly as it relates to software development, software engineering.
One reason it kind of came up is because I've been reading this thing called the Composable Codex, which is a thing written by some data scientist at Voltron Data talking about this idea of composable or modular data systems using open standards and things like that.
>> Am I supposed to ignore the Voltron reference?
Like the lines come together to form a giant robot.
That's the composition right there.
>> Yeah, I don't know if that's intentional or not, but it is a good company name.
It's this ecosystem of things like Aero and Parquet and various Apache projects.
And the idea is that you can take these pieces and assemble them into a data system instead of having to roll your own.
And there's pluggable pieces that everything from connectors to SQL databases to pluggable query optimizers and things like that.
So nice idea.
I've been trying to look at the world of workflow tools in the data engineering world, sort of on the ETL side.
So there's Airflow, which I think most people have probably heard of in that field.
And then there's probably a dozen other ones that are in common use.
>> Workflow tools.
So pipelines, data pipelines, extract, transform, load, that kind of junk.
>> Yeah, and there's many of them now.
There have been many of them for years, but Airflow is probably the most prominent one.
But there's DBT and Kubeflow and Dexter and I don't know.
>> Argo workflows in the Kubernetes world.
>> Yeah, bunch of them.
And I'd also had a friend show me this tool that he uses in the field of computational chemistry, which is another thing where you sort of plug boxes together.
And so anyway.
>> What is that?
Is that a low code or no code thing?
Is that what that is?
>> Yeah, it's kind of a low code thing that you can do to sort of do these repeatable steps.
But it's very specific to that chemistry vertical.
So it has boxes that do things that are common in that field, but not things that you would probably do in a generic data engineering role.
>> No, well, I don't know chemistry.
Would one of those boxes be like, "Okay, and here's where I want the explosion to happen?"
>> Theoretically, yeah, you could put in a box that does reactions.
I mean, it would be a simulated explosion, but, you know.
>> Here's where I want the toxic gas to start coming out and filling the room.
Is that what you would do?
>> It would be things like, you know, reading representations of molecules from a file.
There's a tool that's been around for many years called KNIME, or KNIME, KNIME, that's sort of a general tool in the data engineering world that is very similar, Pentaho.
>> Or Databricks?
>> Yeah, Databricks is a good example.
I think they focus on doing things like spark type runs and things like that.
But yeah, anyway, ETL workflow tools, and I got to thinking about, you know, this is a type of composition, and how does this compare to the sorts of composition we do in regular software engineering and so forth?
>> Yeah, that's my question as you're talking about it.
Is this similar to function composition?
Is this similar to preferred composition over inheritance and OOP circles?
They talk about that.
Is this some abstract concept that is very pure, like pure in its ideal form, that can be just generically applied?
Or is it different when you're talking about, I'm composing pipelines and workflows.
I'm composing things in like bash when I pipe one thing to another and I turn that into a function.
Are they related?
>> I think the conclusion I came to is that these workflow tools are basically doing function composition.
But it's interesting backing up, you know, typically, there's sort of two flavors of these.
One is that you have boxes that have particular inputs and particular outputs, and then the outputs from one box connect to the input to the next box.
And so it's very much like function composition.
And then there's other tools where it's really not so much about the inputs and outputs as it is about the dependencies.
So you're just saying, I'm defining this step, which creates some sort of data asset, but this step depends on this step and so forth.
And with those dependencies, you end up creating a DAG, a Director Day Cyclic Graph, that defines the sequence in which those things happen.
So I also started to wonder, you know, can you think of a Director Day Cyclic Graph as being a sort of composition in itself, even if it's not, even if there's not a specific connection between the inputs and the outputs of various steps?
Well, DAGs and workflows also suggest what people do with CI/CD pipelines.
That probably goes back to, you know, make at least.
So if you're talking function composition, that makes me think of Lambda calculus.
And it's hard for me to, as a former Haskeller, it's hard for me to think of composition, function composition without thinking of Haskell.
And you're talking inputs and outputs.
Haskell gives me a language where I can immediately think, oh, like a function that goes from A to B, type A to type B, that's a type variable typically in the Haskell world.
Lowercase A is like, it could be a type A, it could be a function that takes a type of whatever A's and turns them into whatever B's.
But that it does go all the way back to Lambda calculus.
This is a pretty old idea, I would think.
Do you agree with that?
It's been around a long time.
Yeah, I mean, it goes back to Lambda calculus and it goes back even further in math in general.
I could not surprisingly find a good historical reference for the first reference to function composition in mathematics.
Okay, so I've got a f of x and a g of x, and I want to apply g of f of x.
That's a function composition right there.
Yeah, so I think that probably predates Lambda calculus.
I'm sure it does.
Probably. [laughs] Yeah, probably.
You know, it is interesting that function composition in computer science goes back to before we actually had computers.
Of the workflow tools where they're specifying the inputs and outputs, I think you can think of that as a sort of function composition.
So, you know, you connect box A to box B, and there's an input that goes into box A, and an output that comes out of box B, and you can sort of think of those two boxes as being a composition of functions.
It's interesting though, because you can also think of it as being a sort of modular software, so you can sort of think of it as being a structural composition as well.
That's what I wanted to ask you first.
Does this go back to the '60s structure programming, that type of stuff?
The structure idea, I believe, does.
And so, I think in the 1960s, people started thinking about modularity at least.
So, you know, we've talked about a lot of this stuff on previous episodes, and we talked about complexity on a couple of episodes, and how Herb Simon and his work sort of famously came up with this idea of things become less complex when you build them in hierarchies.
So, you know, if you build small pieces, and then you take those small pieces and assemble them into a larger piece, that is a less complex way to build things than trying to take all of the individual parts and assemble them into a whole at once.
And so, you know, I think that idea was there in the early '60s, and then, you know, in the late '60s, people like Dykstra and Parnas and Liskav, who we've talked about, started to think about how to make software in such a way that the pieces could be sort of separated into modules and plugged together and reused and things like that.
And so, you know, a lot of the ideas that are now sort of common software engineering, I think, started in the '60s and early '70s.
Well, okay, but wait a minute.
When I think of abstract data types, I think of like, "Oh, I've got this class and it represents the car," and the car may have children classes, which are wheels.
That's a little different than composing, right?
How does this relate to this idea of people talking about preferring composition over inheritance?
You've heard that before, haven't you?
I've seen people write it over and over again.
Yeah, it's strange.
If you Google for composition in software engineering, almost every result you get will talk about this idea of it being an aspect of object-oriented programming.
Well, describe it to me.
Let's say you've got me and I'm like, "I don't know object-oriented programming.
What are these people talking about when they say I prefer composition over inheritance?
What the hell are they telling me to do?"
Well, composition in general in object-oriented programming is pretty straightforward.
It means just what it sounds like it means.
So you have a part, an object, and it has subparts.
So you can think of this as being like, "I have a car object, which has wheel objects," and so forth.
Well, what if I have a green lion and a yellow lion?
Those are both lions.
Yeah, and I want to compose them into something.
Sorry, go ahead.
Trying to compose them into a, "What does yellow and green make?
Is that blue?
Is that blue?
Well, no, it's like a Voltron.
That's what was the reference there.
I've got a green lion and a yellow lion.
If I had a red, a blue, and a black, I could compose them into this ship-destroying robot with a big sword.
Yeah, that's a type of composability, I think.
Is it?
But why would composition be better than inheritance?
Inheritance is like, "I've got this generic animal thing, and I've got this cat-specific version, which inherits from animal, and I've got a dog version, which inherits from animal."
Why is composition better than that?
Yeah, so going back to the car with wheels example, in that case, you're not talking about something where inheritance would be a choice.
So a wheel is never probably going to be a type of car.
You could probably make some sort of very abstract base thing, where you call it a car part or something like that.
And I'm guessing people have done that.
But the objectorian of people call this, call the inheritance relationship, they call it an "is a relationship."
So lion is a cat.
And in composition, they call that a "has a relationship."
So a car has a wheel or has wheels.
And there was this idea, I can't actually remember who originated it, but there was an idea that in objectorian programming, you should prefer using the "has a" relationship, even in cases where you might potentially be able to apply and is a relationship.
Okay, but why?
I've heard this before, but why?
Well, I think the idea is that there's two reasons.
One is that a lot of times, if you're trying to do inheritance, you end up with weird things where you have multiple inheritance, which some languages don't support, or you end up with this thing that has, that is a certain type of object, but then has a bunch of interfaces that it implements or something like that.
And people regard that as being fragile and a little bit complex.
And so there was this idea that in some cases, you could use the "has a" relationship to make related things be composable rather than inherited.
And it makes it a little bit easier to swap them out.
It makes it a little bit easier to modify underneath because you're really just talking to sort of an API at that point in time, or a signature at that time.
As with all object-oriented rules, it's one of those things that strut it out as a, this might be a good alternative for you and turn into, this is the dogma of our field.
And if you don't do it this way, you are wrong.
But this fuzzy rule is the dogma.
Do it the way I do it, or don't do it at all.
So you sent me a Bartosz-Miluski post.
I've actually read this post before.
Many times Bartosz is well-known in the Haskell world.
He started out, he's like a physicist, I think, if I have that right.
He was, yeah.
He was a physicist, and he wrote a lot of C++ as a physicist.
He got very good at C++.
And I can't remember, I know I've read him tell the story, but he got turned on to Haskell, and he was like, wow, this is so much more elegant than writing C++.
That's a weird, weird kind of, and then from Haskell, he got way into category theory.
I think I might have that right, or maybe category theory first, I don't know.
So he writes all this stuff about category theory.
And category theory is a little bit adjacent to Haskell.
It inspires ideas in Haskell.
And category theory, if you've never heard of it, is this very abstract branch of mathematics, which is like, what are the pure ideas that populate all the different areas of mathematics?
And can we talk about those pure ideas so we can compare different wildly diverse branches of mathematics with each other?
It's sort of C behind the curtain when they're doing very similar things.
Now, I say all that and immediately say that, every time I've ever read something about category theory, I get about 2% of the way in, and I'm like, oh, this is making sense.
And then immediately after that, it goes wildly off the rails.
I'm completely lost.
I have no clue what they're talking about.
Absolutely do not understand category theory.
Yes.
Same to a certain extent.
His book, Bartosz Mielewski's book on category theory is actually a pretty good introduction if you are a programmer.
So he, in this post, he says, how do we solve problems?
This is a quote from his post.
We decompose bigger problems into smaller problems if the smaller problems are too big.
We decompose them further and so on.
Finally, we write code that solves all the problems.
Is this a little too simplistic?
Sorry, I'll keep reading.
This is continuing on.
He writes, and then comes the essence of programming.
We compose those pieces of code to create solutions to larger problems.
Decomposition wouldn't make sense if we weren't able to put the pieces back together.
So Bartosz here is talking about how composition is fundamental to programming.
It is what you do when you write code.
You compose functions.
And it sounds potentially right, but I have to say my gut response is, I don't see a lot of people who I work with on a day-to-day basis writing code like this.
Do you?
I think composition at the functional level is fairly rare.
I mean, I think it does happen informally.
You write a function and that function returns something and another function which calls that function.
It does happen.
I don't think people use it as a design principle.
One thing that got me thinking about composition and why I thought it might make a good topic is that I hear this argument very often, that decomposing problems into smaller parts and then putting them back together is sort of the essence of programming.
And I think that is basically how we have worked at this field since at least the 1970s.
And so what got me thinking about it was, why don't we do it better?
Why is it still so informal and ad hoc?
Why isn't it more formalized?
Why isn't it more rigorous?
It still seems to be in 2024 largely a, for most people at least, largely a sort of informal analysis project.
And I think maybe the answer to that is because you need no category theory to make it formal and nobody wants to learn category theory, but I'm not sure.
Here's, let me try to restate what I'm hearing.
I think what you're suggesting, and I had a feeling similar to this maybe when I did Haskell more, was beneath what we're doing are these fundamental relationships of information.
When we write software, we are communing with this, the rules of the universe, about how information can be composed and decomposed.
And the way to express that maybe contemporarily is to go deep in a category theory.
But that most of us, and I would include myself in here, when we learn to write software and we continue to write software professionally, it's more like having an apprenticeship as a landscape painter.
That we have practices, best practices, quote unquote, that we follow.
We know the trees that are behind the other trees have more blue because there's more sky there.
And we know the mountains are these abstract lobby shapes, but that some of our trees are happy trees.
That's sort of what you're saying, am I restating it right?
I think there's a definite commonality there.
So I think there is this idea that when you start, you are sort of like the guy who does the trees in the background.
And you will eventually work your way up to understanding perspective and color and keep getting the details of the face right and all that kind of stuff.
But like you say, it's kind of like, here's how we do it, to go practice that and get better at it and pass it on to the next person.
And we don't really, I don't think at least, I don't think it's taught in schools and I don't think it's taught in as a junior engineer.
I don't think you learn any real formal approaches to building software as a composition of pieces.
But when you say you don't learn formal, I think to myself, oh, does that mean I got to learn category theory?
I don't want to do that.
Do I have to learn to formal?
Can I just continue with my gut level of response?
Yeah, well, that's possibly why it doesn't happen.
And maybe if you're a O'Cammell shop or a Haskell shop or something, it's different because in that situation, things like function composition and higher order functions are not really optional.
Those are things you have to understand to be able to build programs.
Maybe in certain paradigms, there is a formalism to it.
But at least it has been my experience that breaking down problems into their component pieces is still largely a matter of taste.
I want to talk about Haskell as an example here.
So in Haskell, function composition is just an everyday thing.
It's just one of the keywords or tools or whatever of the language.
In Haskell, you just use a dot to compose two functions.
And people often write this in what's called point-free style where they don't actually show those functions taking arguments.
So I might have a function like, is this an odd number?
And I might have another function like that inverts the Boolean value, like not, and I can compose this together, like not an odd number.
And I would get even and then you might think, well, that sounds like a tributary dumb example.
But the actual syntax of this in Haskell is like, I take my not function and I write dot and I write is odd after it to compose those into one bigger function.
It's like there's so little text that I write to express this idea of composition.
If I have a function that takes a's and produces b's and I have a function that takes b's and produces c's, I can easily compose them into a function that takes a's and turns those into c's.
And it's this incredibly powerful technique that can get bigger because in Haskell I can have a type that takes another type and I can compose those into ever greater types building bigger boxes.
So the whole idea of like OOP, Prefer composition over inheritance and function composition, which sound different and maybe even UNIX pipes, right, where I'm doing a thing and I pipe it to another thing and I pipe that to another thing.
All of these in Haskell are expressed with this dotted form.
Like the composition in Haskell is completely every day boring prosaic and there's a really weird feeling you get where you realize, wow, this is extremely powerful and completely every day.
You go to other languages and they don't have that.
And there's this weird disassociation.
You feel like, wow, it'd be pretty useful to have that composed dot in Python.
I mean, here's what Bartaj says.
He says, I wish I could tell you that there is a template in the C++ standard library that takes two functions and returns their composition, but there isn't one.
And when he says that, I'm like, yeah, I feel that way about Python.
I had this conversation with Raymond Headinger on Twitter many years ago.
Raymond Headinger, this is a little bit name dropy.
I apologize.
Raymond Headinger is a C Python core contributor.
He's been involved in Python for decades.
He does, he goes to, he helps organize.
He's like one of the main people you would identify with the world ecosystem of Python.
And I was like, I really wish we had function composition in the standard library.
And he was like, it's easy to write that.
Just write that yourself.
And I went, yeah, but it's like, it's an important idea.
It should be there.
He was right.
It is easy to write it.
I wrote it.
Many people have written it.
It's so easy to write that it feels like we don't need to add this to the standard library.
But adding it to the standard library gives it a stamp of like, yes, this is a thing that is fundamental to programming.
I have a function.
I want to map over a collection.
And I have another function that I also want to map over the collection.
If I could just compose those two functions and map that new function over the collection, boom, we're in business.
I guess my question for you is, it feels like this concept is equivalent to like the penny in our monetary system.
It's like underneath everything is the concept of a cent.
It's a very important concept to have, like zero.
And if you saw a penny on the ground, you wouldn't pick it up.
You'd be like, who wants that?
Yeah, I think people are trying to accomplish the same thing, whether they're using composition in object-oriented style, or they're building workflow tools where you plug the boxes together or they're doing functional programming.
I think everybody's trying to accomplish the same thing.
There's this intuition that we have about composition, that we can take two things and make them a new thing.
Or we can build things in a hierarchy.
Or that we can take types of things and make a new thing out of a collection of those types and get the same type back in the gang of four book going back to the '90s.
There's a composite pattern, which basically treats a tree of things or a collection of things as a thing in itself.
So the collection of things and the individual things are sort of in some sense the same type.
I think what happens is that in the functional languages, these ideas are trying, they try to formalize these ideas.
So you have, you have functors and you have monoids and these things that are, you know, essentially about composition.
But when most programmers encounter that, it's like, I don't want to know about this.
It's like, it's too abstract.
It's too out there and like non-graspable, maybe, right?
It's too, yeah, I don't really think these are hard concepts necessarily, but there's just something about them that I think is to certain programmers off-putting.
And I don't know why.
I guess partially it's because if you've come from a normal imperative background, that it seems weird and maybe unnecessary at first.
I think one, there is one thing you're saying that I learned from Haskell.
The rule about composition is that it has to follow this law of associativity.
And I think that's what makes it feel like a, a concept that can reduce the mental burden.
A lot of the things that we reach for in our day-to-day work that we say, yes, I'm so glad I have this tool are things that make it easier for us to think less about the big problem.
And when we're talking about composing, decomposing, we're talking about this a little bit here.
But associativity, so if I have G of F of X, it kind of doesn't, it may not matter that much, right?
The ordering, yeah, I have an A to B and a B to C, so I need to produce a B before I can run B to C.
But it's like, I know that all together, it's like, I sort of collapse that into one sandwich.
I can kind of forget about the intermediate parts.
Here's an example.
If I go to a website that sells furniture, I want to look for a couch.
So I've got some search function.
These are e-commerce, very common.
Often I can run like an advanced search.
Maybe I want only couches that are brown, so I've got a filter on color.
Maybe I want couches that are under $2,000.
So I've got a filter, which is like min max for money.
Maybe I've got, I want a couch that's made out of cotton or wool or something.
I don't know what couches are made out of.
So these filters can be composed together, and I could turn them on or off, and they don't care about each other.
All I know is I just sort of blob them all together, and what do they produce when I blob them together?
Each individual filter composed with all the other filters becomes overall a filter.
That to me is the essence of composition.
And that's what makes it powerful.
And it's that associativity that makes it so that I don't have to think about.
All I know is I just sort of smash all these things together, and I get a new bigger function out of them.
Does that make sense as an example?
It does to me, and I think one of the benefits of thinking about this in functional terms, as opposed to structural terms, is that it's more obvious that you can do things in parallel.
There's sort of a direct scaling idea in functional composition that I don't think is quite so apparent in the structural idea of composition.
That didn't occur to me.
Can you give me an example?
What do you mean by that?
I was afraid you'd ask that.
So the associativity thing is the important thing.
So if you have three functions, f, g, and h, the associativity thing says that wherever you put the parentheses, that still works.
You don't necessarily have to do it right to left or left to right.
So I have this gut level response.
When you start talking about composition, I think, yes, this is an extremely important concept.
But outside of the people I've talked to in the Haskell world, most people just completely ignore this concept.
And then if you explain it, they kind of go, yeah, so what's the big deal?
But maybe one way to talk about how it's a vital concept is to talk about places where things don't compose.
Now, I noticed in your Haskell example, you said monoid and functor.
I don't think you mentioned applicative, but these are all things that are composable in Haskell.
There is a well-known thing that is not composable.
You cannot compose these together.
And those are the dreaded monads.
So if I have a monad that wants to print to the screen, that's the I/O monad.
And I have a monad that wants to have some state carried through it.
That might be the state monad.
Or I want to inject some, like almost dependency injection, that'd be the reader monad.
I can't compose reader state I/O.
And this is the heartache and the frustration that people have after they've been doing Haskell for just a little bit of time.
They start to grasp the monad.
They grasp composition.
And then suddenly it's like, nope, sorry, friend.
You can't put those together.
And in fact, to put them together, you got to do this big crazy thing that we call the monad transformer, which knows how to pull apart the guts and reassemble them every time you want to run a particular operation.
So those are non-composable.
So what you're telling me is that if I have two burritos, I can't combine them together to make one big burrito?
No, because it's like, you don't know how much hot sauce you need for the big burrito.
You can't mash them together.
That's true.
You're right.
You can't take those tortillas and blend them to make a giant tortilla.
Very good analogy, actually, the burrito analogy there.
I'm still cursed by the monad as a burrito analogy.
So I know it doesn't work.
Famous joke, famous joke.
So monads are not composable.
And this is part of the frustration with working with them, actually.
It's what makes them sucky to work with.
You can't just wrap one inside another easily.
You have to use some other data structure that knows a lot about how they go together.
That sucks.
I'll give you another example.
And you are not going to be surprised by this example, because I've been complaining about it for years, and I've been complaining about it since we started working with this tool.
I think it was maybe 2016 that you and I did Airflow.
And this complaint may be horribly out of date.
But at the time, we were already doing Python, we were doing Celery.
Airflow was like, oh, yeah, that sounds cool.
This is kind of like a next level.
They provide this nice website where we can manage our different tasks and we can pipe the tasks together.
We can build a DAG.
Now, it seemed to me in Airflow, they're explicitly saying, you make a DAG, a directed acyclic craft.
I thought that was empowering.
It wasn't intimidating to think in terms of, wow, I got to thinking about computer science, the aspect of it.
It was already like I had heard of a DAG.
And it was a useful way to think about a workflow.
Here's the DAG you're building in.
Now, here's what annoyed the crap out of me.
In Haskell, if I want to make a tree or a graph, it's a recursive data structure definition, usually.
A tree is a leaf or a tree.
That sounds a little weird.
But you could think of a single node in a tree as like the least, the smallest possible unit.
And that node may have connections to another tree.
And a tree is ultimately composed of a bunch of nodes.
So you could think of like it's recursive.
It's like it's easy to combine two trees.
Because a node is already connected to a tree.
Maybe it's a binary tree, so you've got a tree on the left and a tree on the right.
What's in there?
Well, you can recursively inspect that thing.
I may be doing a really bad job here.
Anyway, so in Airflow, you build these DAGs.
Once you have a DAG, I thought, oh, you know what?
I already have this existing DAG from this DAG.
I want to call that other DAG.
And in order to do that, I had to use this special concept of the sub-DAG.
And I was immediately like, this is obnoxious.
The DAG isn't just a composable data structure.
A DAG should be able to have a link to a DAG.
It shouldn't have to be this specially treated thing called a sub-DAG.
It's not composable.
And as a result, I was immediately like, oh, I don't really like this Airflow thing.
I don't like the way in which they've put this together.
It seems like more landscape painting than category theory.
Yeah, I think when people are trying or thinking of composition, or if they are sort of doing it unconsciously, that's what they want to achieve.
So I've put these things together.
And now this thing that I put together, I should be able to treat as a whole.
Yeah.
And when that doesn't work, it feels wrong somehow.
But I suspect that to think about this stuff formally and make all the versions of composition that we've been talking about fit into the same conceptual framework, you probably need to do something hard.
You probably need to do something that's more difficult than I can handle.
And I based part of my speculation there on this thing.
I've tried to read a couple of times.
It's kind of a book slash long paper by Fong and Spivak.
It's called Seven Sketches in Compositionality and Invitation to Apply to Category Theory.
And it's really appealing when you start reading it, because they talk about how you can sort of formalize this idea of what they call wire diagrams, which look a lot like the workflows that we see in some of these workflow tools.
And it makes perfect sense at the beginning.
And then at some point you hit this wall, depending on your mathematical sophistication, you'll either hit the wall and make some progress after that or hit the wall and be rendered unconscious.
But it seems like for almost anybody who's a run-of-the-mill programmer, you hit this point where you just have no idea what they're talking about anymore.
I reached the part in the first chapter where they started talking about Galois connections, and I just go catatonic.
You said this to me, and I've actually read that first chapter a couple of times.
And I had that same feeling.
It's like, oh, I'm 2% of the way into this text about category theory, and I've driven myself completely off the cliff.
I have no clue anymore.
There's no ground underneath me.
And I open these texts like, wow, these people are talking about fundamental relationships of information.
They are opening a treasure chest of the way stuff really works.
That's the promise.
But the payoff often is like, well, it's too ethereal for me.
And it often is very hard for me to map it back to actual things that I use on a day-to-day basis, real concepts that I interact with.
It's a struggle.
I have the same thing.
I keep trying to think of how would I render this in code?
They do have some interesting ideas that I sort of get, and they use this word compositionality.
So there are, I think, things that we think of as being composable, but in their world, they would not have compositionality.
So here's a quote from this book.
In this book, we explore a wide variety of situations in the world of science, engineering, and commerce, where we see something we might call compositionality.
These are cases in which systems or relationships can be combined to form new systems or relationships.
In each case, we find category-theoretic constructs developed for their use in pure math, which beautifully describe the compositionality of the situation.
So as we motivate this first chapter by noticing that while many real world structures are compositional, the results of observing them are not.
The reason is that observation is inherently lossy.
In order to extract information from something, one must drop the details.
So this sounds perfectly reasonable, but this last part is a little tricky.
So what they mean by observing them is hard to explain.
I think some examples they give is you have a structure and you apply some function to that structure, which describes the property of it.
And for structure A, it's true.
And for structure B, it's true.
But when you compose structure A and structure B, it's no longer true.
In their view, those things would not be composable under that operation, because when you compose them, you end up with this new emergent property that was not true of either of the pieces.
They give an interesting example in the book about poker hands.
If you have a poker hand, which is five cards, so you have H1 and H2, which are poker hands.
And you have G1 and G2, which are poker hands.
And you can say that G1 is a better hand than H1 and G2 is a better hand than H2.
But then if you apply a process to them, where you take H1 and H2 and you take the best five cards out of each set, H1 and H2 combined might be a better hand than G1 and G2 combined, even though G1 and G2 are better individual hands.
So again, they would consider that to be something which is not composable under that particular operation.
So I guess the thing I'm trying to convey here is that in their description, the composability of things is you kind of have to ask the question, composable under what operation?
So when I gave that example as a furniture website, many years ago, I had to build something similar to that, but I didn't see it immediately.
I was describing something and then someone at work said, well, we need to produce this type of experience for our users on the web.
And I went, oh, and they started describing what we want to be able to do this and that and this.
And I blurred it out.
This is when I was doing a lot of Haskell.
It's a monoid.
So then once I had this inside, like, oh, that's a monoid, what you're describing.
I immediately knew how to write this.
This was in JavaScript.
So I immediately knew how to write it in JavaScript because I just wrote function composition over monoids in a JavaScript version of what I would have done in Haskell.
And that may sound horrible.
You might be cringing at that thought, but I think it was actually pretty readable.
It was like, I had all these filter functions and it was trivial to compose them.
They would take similar inputs and produce similar outputs.
They would take an A and produce an A similarly.
Anyway, once I had the insight that it was a monoid, it was easy for me to write.
When I went to other people and they're like, what are we doing here in this section?
I would say, oh, that's a monoid.
Their response, and I think justifiably, would be so what?
I think of composition in that way.
It's very powerful if you see it as this pattern that underlies things, but it doesn't tend to help people if they don't see it.
I am not entirely sure.
I like that reaction, I guess.
I guess I feel like this is something that should be more commonplace.
I think computer scientists, programmers, should probably understand the concept of monoids.
I know it sounds like this fancy category theory term, but the truth is, the idea comes up everywhere.
It's ubiquitous and it just seems like having this piece of terminology that you could use to talk about these things would be convenient.
I don't know why this idea is not a hard idea, so I don't know why it scares people like it does.
I don't even know if it scares people.
It's like if I came to you and said, maybe not you, if I came to somebody I worked with and said, hey, all these apps you've written over the years, they all share these fundamental features, which are extremely abstract concepts.
I could draw a connection from application A to application B to application C.
They're all fundamentally doing this one concept.
I'm going to give you this abstract name for it.
It has these properties, these laws it adheres to, and it has these relationships internally.
Their response, I think just if highly might be, I don't care.
A, F/A works, F/B works.
It doesn't matter to me.
Oh, that's a neat insight, but is it really valuable to me to connect them in this way?
Now, I agree with you for my own work.
I like to be able to see behind the curtain that there may be information patterns governing the behavior of what I've written.
It helps me get a little more quickly to know what are the features or properties of the way this information should flow through my application, but I'm very much more on the side, and I'm like this for everything of saying, "If somebody doesn't find that valuable, that's fine.
It's probably not that valuable."
I think it's mostly just a matter of the language of the field.
The landscape painter-ish aspect of it.
We're all apprentices, right?
There's this famous essay by Hamming, a Hamming code fame, where he talks about how the general point of the essay is how to become great in your field.
He lists a lot of things about how hard you have to work and the types of problems you have to focus on and things like that.
But one of the points that he makes in there is that a lot of times, scientists are very imprecise about their language.
I actually saw him give this talking in person one time at UCSD.
He was talking about how he was over eavesdropping on a group of engineers at a table.
This was probably at Bell Labs.
They were talking about some problem, and various people were using the word "dissable," but they were using it in a way that did not have the same meaning for each of them.
He was talking about how this is frustrating to him and probably also detrimental to these people.
They were not communicating well because they were using these terms in an imprecise way.
The word "monoid" sounds scary and weird, but I also think if you know what that means, it's a way to communicate something that is more informative than doing it in an informal way.
So what you said about hamming there reminds me of Leslie Lamport saying that programmers, software engineers, computer scientists even are too afraid of mathematics.
Mathematics is much more precise language.
They should be using mathematics to express ideas and demonstrate that they're correct, but they're afraid to do that.
I hear Lamport say that, and I say, "Yeah, you're probably right, but I'm going to continue to be afraid of mathematics.
Okay, I'm just hide over here in my corner."
Fair enough.
All right, Mike, composition, extremely important topic that barely anybody cares about.
Thanks for talking about it with me this week.
You're welcome.
Well, this is Bitpicture Recoding with Eric Baker and Mike Moll.
My name is Eric.
Thanks again, Mike.
Nice talking to you this week.
You're welcome.
See you next time.
Bye-bye.
Bye.
[MUSIC]