 I'm going to try and go through this concept, which is really kind of near and dear to me as I was learning about this interesting thing called free, which I think we've already had a little bit of exposure to if you were at an earlier talk today, the one right before me. I want to think of this talk as an advanced talk in the advanced track, perhaps what I also want to think of it kind of as an FP 102 thing of that I think this is a learning experience that people run into, they bump into free monads and they want to understand what do they mean. And so what I'm going to try and talk about in this talk is sort of one pathway that I kind of took to understand free in an increasingly general space of things and how that kind of intuition was helpful for applying it both in the very practical, how do we use free monads and also what does it mean when we see the word free being thrown around so freely. So without any further ado, let me dive in, oh, one more thing. I'm trying to manage time on this, there's a lot I want to cover but I only have half an hour but also if I go too quickly, feel free to ask questions, I love questions so, yeah, let's get started. So like I said, the thing that I want to talk about, the main thing I want to talk about is ways of seeing freedom. A lot of times we bump into freedom first as a noun, a very particular noun which is written in a monotype font, free, free monads. We can actually take that several steps to make it more and more abstract and hopefully by making it more and more abstract we're going to get a greater understanding of what even that very initial single free monad noun that we started with actually means and why it's so important. So I'm going to walk through three ways of seeing free. Ultimately what I really want to kind of get to is this final one though, seeing it as a verb, seeing it as a process and so if we spend the most time talking about that one I think that's an ideal place to land. And then finally I'm going to be using not real category theory that's like just beneath the surface, I'm going to maybe say some category theoretic words, at least one of them, but a lot of this is not necessarily actually category theory and if anyone is going to take it from a category theoretic perspective, just sorry, but the intuition that you can get by looking from it by using the terminology of category theory, using the like inside of category theory can help you to understand things and so hopefully that's what I kind of want to demonstrate a little bit is how this intuition, language and mechanism can be used to understand things that we play with in programming languages. So first up is free as a noun, which is exactly what we just talked about in the previous talk and what I think a lot of people have bumped into, it's a pretty common pattern just for programming very, it's a tool that people love to use in Haskell and Scala and other functional programming languages. And so what you usually see is you see something like this, free, F-A, return, free, what is this thing? It's a data type that doesn't necessarily speak monad to you except in that it says return maybe. It's not entirely clear how this relates to something that you would think of as monads as you're beginning to build intuition about like maybe or either or IO or something like that. As we talked about just in the previous talk, you can kind of see if you're used to looking at things in pattern functors and recursive functors that it's this gluing together of the identity and the fixed point. Again, it's not entirely clear why this should give you a monad, but it does somehow. In particular, yeah, I don't know, something kind of like identity and fixed put together. So the question I had when I first found this thing, I first started reading like the free package. I started seeing all these people really talking about how exciting free was. I was like, what is this thing? Why does it work? Why is there any real meaning to it? And so we want to look at things more than just the types. The types are a good place to start, but ultimately the operations are where the real work is done. And so if you look in like the free package of the Haskell free package or anything, you'll see a bunch of these different operations. And I want to focus on just these two. The secret is that these two are pretty much the key operations that you need to understand free. You'll have used the first one, lift. Lift is when you take, as we probably should say this explicitly, what you use with free, the free monad is you take a functor, a pattern functor, which may describe different operations that you want to do. And you lift it up and create a monad with it. And then you can use all of the monad structure. And it will be based on whatever the functor that you passed into it was. So the first thing that you use is this lift. It takes your functor argument, whatever your functor is, and it injects it into this free type. And the second one, called fold-free, I'm calling it fold-free, says that if you look at the last half here, the last part that I parenthesized, it's a way of interpreting a free monad, free of some f of a, turning into some m of a, which we know is a monad. And so what I want to begin to shape your intuition about is that if you have functors, you're going to be lifting elements of the functors into the free structure. And then you're going to be folding or interpreting that down into monads. And so free itself exists in between functors and monads by allowing you to take this circuitous path. So before I get too abstract in this, I've given you a little bit of impression. Let's go ahead and run through a really quick example of using this in a more practical sense. I'm defining this functor at the top here called teletype f. It's a pattern functor. It gives me two patterns. It gives me the put-string line pattern, which, if I give it a string and an extra slot, a recursive slot, then that's all of the information we need in order to execute a printing command. And git line is packaged along with a function that if you know what to do with a string, git line will provide that string to the function, the continuation, and you'll be able to move on to the recursive argument. So hopefully, people have at least seen this before. I don't want to spend too much time on this particular example, but if there are any questions about how this is working, feel free to ask. We take this pattern functor, we hit it with free, and we create this thing that's teletype, and it turns out now because of the structure of free teletype is a monad. So ultimately, we'll be able to write using do notation or any kind of monadic structure that we want. We'll be able to write little monadic fragments like this. This is a echo teletype function. It's just going to forever git a line and print it back out at you. And so it looks very much like a normal monad, but we constructed it interestingly just by using this pattern functor and then smashing free against it. Now, the other thing to note here is that I use these two smart constructors. I guess you could call them to build the data types that I'm using over here, the git line teletype and put string line teletype. And these are where we're applying this lift for the first time. So put string line of some line in the unit. If we lift that argument of teletype f. So if this is our regular functor and this is the argument of the functor, when we lift it, that ends up in the free teletype f of that argument. So we use lift to construct elements of our free monad from elements of our functor. So that's kind of the trick that we're using here. The functor is pretty simple. We don't have to worry about what that's doing too much. It just holds some things for us. And then we use this magic free thing to lift the functor up into the monad. Once it's in the monad, we can go ahead and treat it as a monad. We can use do notation. We can use any other thing that operates on monads normally. And the final thing we want to do is we want to build an interpreter. And so if you look at the bottom here, the echo IO function I have, it's an IO monad. And a computation, which is occurring in IO. And we built it directly from the echo TT, which was a monad in teletype. And so we've been able to take this teletype monad and inject it directly into IO, interpreting it as IO. And to do that, we use this fold. Sorry, I made a mistake here. This is what I was calling fold free back on this slide. So fold free applied to this interp thing, applied to echo TT, interprets echo TT as IO. And so the interesting thing we need to think about is what is interp. Interp is simply taking any layer of our functor, a single element of the functor, teletype F, and treating and being able to interpret it as IO. And so if you think of free as being able to take your very simple functor pieces and injecting them into a monad, interp is saying if you can tell me what the meaning of any one of those very simple functor pieces is, I can extend that meaning to your entire monad and allow you to interpret in this case the teletype monad into IO. And so we can see in interp here, all I'm doing is examining the functor. If it's the put string line functor, I have a line that needs to be putted. So I go ahead and apply the IO operation to put a line and then I return the thing inside of the functor. And if it's the get line, then I have this next, which if we remember is a continuation from string to A in this case. So I need to use IO to get a line from the environment, pass it to that continuation and then go ahead and return the A that pops out. There's a little bit of mystery here around what that A is. In particular, it's if you remember, if you, anyone who is in the previous talk, we noticed that we often use the final, the functor argument of types like this recursively and that's what we're gonna end up doing here as well. So what's important about interp is that while it has to play with the values of the type A, it can't examine the values of the type A. It's transparent to interpret. Interp has to be invariant to whatever A is. And indeed, if we look into libraries and look into this interface of free functor or free monads that we've been introduced to, we noticed that we have a for all there which prevents us from actually examining whatever the argument is. So that's going pretty quickly. Hopefully I'm not completely losing anybody who's interested in what's going on with free monads but what I wanna really harp on is the idea that these two functions right here, lift and fold free are kind of giving us all the basis of operations that we need to construct our elements of the monad and then interpret the elements of the monad however we need to. And so we have this path again. We go from some simple place. We lift things up into our free structure and then we drop it down into whatever that free structure like this is the free monad, right? So if we drop it down into monads that's the kind of pattern that we're gonna be looking at. So that's free monad, that's free as a free monad, the noun. One thing I really quickly wanna talk about is I was saying earlier that we're getting very nice embedded DSLs for less. Sometimes I think the pun goes too far and people start to think that free here means that you're just getting all of this monad stuff without paying for it. It's a really good pun but I think there's more to this and that's kind of where I wanna go to next is what does free mean as an adjective. So any questions so far is the stuff that is reasonably well covered by this group. Great. So now I wanna talk about free as an adjective. We've were previously saying free is this data type, this constructor there is the thing of the free monad and it's all these very particular things but you can also say that monads are a type of thing, a class of thing, a kind of behavior that we use a lot in functional programming and the free monad is just the free one of those things and so really free is modifying monad and trying to talk about certain kinds of properties that you can have when you free a monad. So we can talk about free making free monads, the data type free makes free monads and as long as we're talking about an adjective we can try applying it to other nouns that we're used to so free monads, monads if people are familiar with are just things that have a neutral elements, a zero and that you can smash two, if you have a monad, if you have two monads you can smash them together to get another of that same kind of monad and indeed we have a notion of free monads. So if we go and look up, look into a library and ask someone what a free monad is and they'll tell you with caveat, they'll tell you that the free monad is a list and indeed if you look at this kind of, these operations that you have, you can see that they have a similar shape to what we were looking at before. Pure takes any value and lifts it up into, this is not a monad anymore but instead lists a monoid and then fold map, which it comes from the foldable type class, takes a function which converts values into monoids and extends that function over your whole list. So if I'll scroll back really quickly to the previous slides here, if you squint a little bit and you erase some of these extraneous type parameters that we get on functors and monads, then the lift and fold free functions right here are more or less the same as what's going on with pure and fold map and that's the kind of intuition that I want to keep everyone's eyes on. So, oh I did it there too. So free makes free monads. At this point when I was learning things I was ready to accept, great. So lists are free monoids because they have the same kind of structure, the same kind of shape. You lift things into them and you interpret them back down as monoids and so lists must be free monoids. You can also look into libraries and find that you can make free applicatives. You can look into libraries and find free things of all sorts of different kinds. Pretty much any type class you can think of, you can go and find somebody who's made a free construction of it and probably that really is the free construction sometimes or not. And so you get this really strong impression that you can just go ahead and take whatever properties you want and find the free thing of it and then you're done. You have this free thing, you can inject things into the free thing, you can interpret it back down and you get all of these nice separations of representation and interpretation. You can go crazy and talk about interpreters existing all the way throughout your language in all these different circumstances and not be totally wrong. Like you're using the same kind of pattern. You're using interpreters and the representations of languages and it's a really cool powerful trick to find. And I think Haskell does a pretty good job of exposing that to you. Another thing you'll probably learn when you start to examine free as an adjective is that people start to talk about free things as being the largest things or the simplest things. And there's a lot of merit to that. In particular, what I'd like to say is that you can kind of read that out of looking at these two things by themselves because fold free at the end here allows us to convert a free, let's look at this one, fold map here allows us to convert a list of As into any monoid that we want because we have that very, very nice property. In some sense, we must have more information with a list than we have with any other monoid. And so if we wanna make the sum of a list integers under addition form a monoid with zero as the identity element in addition as the smashing together element. And so if we wanna sum a list, then we're just taking all the numbers in the list and smashing them together with addition. And so this list has gotten the largest structure of the monoid because concatenation of lists doesn't delete any data. But when we interpret that as a sum, we no longer can find what were the original constituents anymore, but we still have interpreted that list of elements into a monoid and then gotten the result. And so this is where the intuition kind of comes from where you get largest monoid, simplest monoid, largest monads, simplest monads. And for a while, this is a pretty good intuition that helps you to understand why interpreters work so nicely the way that they do and why the lifting function is enabling you to take any functor and stick it up into the largest monoid or the largest monad. In particular, what kind of forms a problem though, this intuition, it's not wrong. It's absolutely the correct way of doing it. But when it's stated like this, and this is the way that I experienced it when I was first asking the question, what is free, is it's not necessarily completely consistent with everything else you might ask. In particular, when I was first learning about free, or one question you might have is, if I'm looking for the largest monad, well, what is free teletype, the largest monad, and free of any other functor, the largest monad? Are they both the same? They're clearly not both the same if you examine free teletype and free list. The free list is a rosetree and free teletype is that interpreted AST that I worked with earlier. They're not the same thing, but we want the common knowledge you would kind of want you to believe that they're both the largest monad. And at this point, people start saying, oh, the largest monad over a functor, over that teletype thing. And it just began to ask a lot of questions about what largest might really mean. Another thing when I was first learning about free monas is around the same time that the free package in Haskell was being actively developed a lot and built up. And there's another one by a Heimrich Atfumus, maybe I'm butchering his name, I apologize, called operational. And at the same time, both people were claiming operational is the free monad and free is the free monad. And again, if you examine the types, they're not the same. They're clearly not the same. They don't behave the same way. And so there's a question. Like, are they both free monads? Are they both the largest free monad over a particular functor? In this case, both free and operational can take the same functor. So it's even more confusing. What exactly is going on here? Yeah. So at this point, I was personally a little bit confused and I was personally unsure of how exactly one should interpret free monads. What is the meaning behind them? So I wanna get moving and try and finish this up pretty quickly now. The last thing, the place where I really wanna leave us with is this idea that freedom isn't a noun, it isn't an adjective, but instead it's a process. And the way I want you to examine this is if we take a look at the kind of free, GHCI will pop out this and tell you that it takes star to star to star to star. Which is a little bit uninformative, I think. Because really what we wanna be looking at when we think about this is it's taking star to star of functors to star to star of monads. And this is the fundamental intuition that I wanna leave you with, with freedom being a process. We have arrows now, so there's processes going on. And we've seen this before if you examine the code straightforwardly. The instance declaration states that we're taking functors and we're turning them into monads and when we turn them into monads, we don't have to have anything else there, we're just doing it for free, right? So now that we have an arrow, it's time to start talking about category theory because category theory almost always helps you when you're thinking of arrows. And so we can examine other kinds of free constructions that we were working with earlier. The free monad takes functors and turns them into monads. The free monoid in this case called list takes anything in Haskell and turns it into a monoid. The free functor, which I'm not gonna go into too much detail here, is taking anything in Haskell which has the type, or the kind, star to star, even if it's not a functor, like really a pathological things like pred A if that's A to William. I hope you can work and convince yourself that you can't make a Haskell functor out of this one, but if you use this type, which you can look up called coionata, you can turn even pred into a functor. And this process is repeatedly going on. There's a source, whatever the basic kind of thing you have is, and then there's a target, the thing with extra free structure. And so whenever you're examining arrows, one thing that you might want to ask is, is there a way to look at other arrows relating to it, in particular, one that goes from the target back to the source? And the thing that I wanna really emphasize is there's a lot of usefulness you can get out of looking at it in this particular way. In particular, if we call the arrow that goes from the smaller thing, the thing with less properties to the larger thing free, which is what we have been doing, then the arrow that goes from the larger thing from monads and turns them back into functors is something that's forgetting certain properties, so we might as well call it forget. Yeah, so the question you might have or the question I had is, forgetting is kind of a clear property, I think. If you've got a monad, we already know that all monads are functors, and so if you just forget about all the operations on monads, you're no longer allowed to return, you're no longer allowed to bind, but you still have the F map that you can derive from those, then you've just forgotten some things, and it's a fairly simple thing to grasp, at least I found when I was learning this. And then that makes you ask the question that if you're forgetting from the monad back to functor is what free doing, simply somehow remembering that structure. And so what you might ask then is if you have some monad and you forget the monad out of it, and then you have a functor now and you free a monad back into it, do you end up with the same structure? And it turns out that that doesn't actually hold, it doesn't hold the other direction either if you have a functor and you free the functor and then you forget it back down, you end up with a slightly different structure as well. And so instead, and this is also perhaps not a really great property to have because it would mean that there's a very strong, like isomorphic connection between functors and monads which you wouldn't expect because they clearly have different kinds of behavior. So instead what we're gonna look at is we're gonna say, let's say we have a monad which is already a free monad of some functor. We don't necessarily know what it is. In this case, it turns out that if we forget it and then free it back, we end up in the exact same place we started. We can do that on the opposite side as well. And this kind of operation where you can free and then forget and then free or forget and then free and then forget and you end up with a free again. There's an item potency here. This is not exactly the definition of adjunction but it's pretty close. It's a property that you might expect of adjunctions. So adjunctions are the category theoretic term that I am gonna very lightly introduce because it is the proper relationship between free and forget. And this kind of operation can give us a lot of insight into what everything else is going on with free. Adjunctions are kind of a scary property of category theory in that people will say things like all concepts in category theory are adjunctions and that means that they're extremely general and difficult to handle. But what I'm gonna do is here's enough category theory to say what adjunctions are but I'm gonna convert that pretty quickly into Haskell because at least we can use this stuff. And so what I'm gonna introduce forget, a forgetful functor in this case or forget is gonna transform monads into functors. And because all of that stuff is ambient, all we're gonna do is we're just gonna pretend if I put forget in front of a monad then after that point we're no longer allowed to use binary return they're gone. And I'm also gonna introduce this type of natural transformations because they're really useful they showed up earlier and they'll help us to talk about this. So natural transformations between a functor F or a type constructor F and a type constructor G at the very least is going to be an arrow, a Haskell arrow where the argument to each one of those things is undetermined like we encountered earlier with the interpreter. And so adjunction in this case the junction that I wrote back here where free is left adjoint to forget is effectively gonna translate into the property that natural transformations from free to any monad from free F to any monad can be converted into natural transformations from F to the forgotten monad. So the monad just as another functor. And we can go the other direction as well. Any natural transformation from functors F to functors forgotten of a monad M can be converted into a natural transformation from the free monad over F into normal monads. So that's kind of scary as well. Hopefully it's a little bit less scary than this one. I don't wanna break those apart into too much detail. I wanna instead just start using them because the claim I wanna make is that forget and free being an adjunction gives you all of the structure that you need in order to understand free monads. And so if this is all the structure that we get from adjunction, I'm gonna use it to construct what we need. So here's just expanding out that type synonym. And then if we take a little bit of notice of the types between backward here and fold free which was what we used to build our interpreters we can notice that they're actually the exact same thing. Fold free is just saying that if we know how to interpret any their functor into a monad then we can extend that interpretation into the entire free structure. And so fold free is exactly the same as this backward conversion from our natural transformations. On the opposite side, if we introduce ID free which is just a specialization of the ID function and pass it into our forward what we're gonna be constraining is we're gonna be turning M into free of F. We end up with our lift function. It just takes any functor and injects it directly into free F. So by seeing this adjunction by seeing that there's a relationship between freeing and forgetting and by seeing that they kind of begin to invert one another but they don't entirely you have to have this whole roundabout free for get free in order to get back to free. We can realize that that's all the structure that we need in order to use free monads. So what is an adjunction bias? Everything. And then the final thing I'm running pretty much over time on my half hour talk here. So sorry if I'm going really quickly but the final thing I wanted to add was there's a really really clever way of representing free structures in Haskell which occurs if we take that backward thing that we were looking at a moment ago and we just flip it. The flip of backward has, it's the same function, right? It's just taking free of a free monad. We're passing the natural transformation as the second argument and then we get any monad back. One of the properties that we can use a lot in functional programming however is that the meaning of something is exactly how you use it. And so what I've kind of indicated earlier is that this fold function is the most general way to use free monads. And so what we're talking about here is we're converting if we were to wrap parentheses around the last two bits of this type signature. We're converting our free monad directly into the way that we use it. And so we can actually define free in this way. I've just taken the latter half of this type signature and wrapped it up in a new type. I have to universally quantify the M because if I wrap up that whole M I don't have any M parameter left so I have to bind it with the universal quantifier. And we get this type here. And it turns out, or we get this type here which can be shown to be a monad, can be shown to be the free monad, can be shown to produce exactly the same structure that we get from the original, the return and the wrap constructor that you might see when you see it in the free package. And in fact, we can do something really interesting and we can now, since monad only exists inside of this type in one place, if we use constraint kinds we can generalize over the constraint and create free constructions of any kind. You can have the free monad plus, the free applicative, all of those kinds of things are suddenly available just by seeing that the adjunction gives you this elimination structure. One of the, the only thing we have to note is that this is a higher order thing because functors and monads take one type parameter. If we want to do it more simply with lists then all of the same process I did before I just replaced the natural transformation with a regular function and you get this free construction again over any kind of thing. So if you replace the C constraint with monoid then this is the free monoid. The real free monoid, not the one that everyone complains about how list isn't really, really the free monoid. This is the real free monoid. And that, that's construction works for any constraint that we want. So there's an example of using it and that's about all I had to say. So hopefully that was at least somewhat illuminating. Hopefully I haven't been able to talk about how we can talk about freedom as being a noun and adjective and then a process and how we can use the property of forgetting to understand a little bit more about free and actually generate a lot of the uses that we have for freedom and even see it in more general light. So thanks everyone.