 Thank you. All right. Okay, great. So, so yeah, I'm Runaan. And I'm gonna be talking to you about the programming language unison, which we're calling a friendly programming language from the future. So it's sort of, alluding to the fact that it's not quite there yet like it's not quite ready where it's still in development so it's sort of from the future but also that it has a lot of what we think is sort of like future programming stuff in it. And we'll get into that. Okay, so I am one of the co-founders of unison computing, which is a public benefit corporation. And it is its mission is to create unison, the language and platform for for that language. I'm one of the authors of these books functional programming and scholar functional programming in Kotlin. I think scala is coming out in the second edition so that's going to be super exciting for scala three. And so you know if you're into scala. But we're not going to talk about scala we're going to talk about unison. So the overview of the unison language is what I want to give you today so not going to go very deep. It's just going to be the big idea. What's the purpose of this language. And we're going to kind of play around with it a little bit, kind of in a, just maybe do a little informal hacking on something. So what is unison well unison is a purely functional, statically typed language, it is strictly evaluated similar to Java or scala, or F sharp. It's open source. So it's all written in Haskell, the compiler and runtime are in Haskell. It's syntactically similar to Haskell. It's also not syntactically but it's sort of conceptually similar to small talk. But it's also radically different from both of these and from most other languages. So why are we doing this why unison. Well unison has unison comes from the fact that we wanted to look at the whole developer experience from from with fresh eyes. So we've been programming in high level languages as a species now for like 60 years, a little more. And we've experimented with lots of programming language designs and paradigms along the way. But most languages in use today are not that different from Fortran or alcohol. And software development has since evolved a lot, even though the languages are very similar. And there's all this other stuff that we do as software developers that we don't get to use our languages for things like version control and collaboration and builds continuous integration and then, you know, getting your code deployed with software, distributing it, distributing it to customers or clients, you know, getting public publishing software, sharing libraries, and then of course ops, which is like running the actual systems that we build. And all of that is done with with sort of pragmatic and incremental solutions, which are built upon assumptions of whatever came before, and it all kind of hangs together with the ammo files and unix. And very little of it is thoughtfully designed, like with the programming language or with the programmer experience in mind. So databases are still mutable bags of text files and, you know, we share them around with with git or version control that doesn't really understand anything about the structure of the code. And then distributed programs are talking to one another with ad hoc protocols that are described out of band using some kind of technology that requires like legions of programmers to maintain or you know there's often that one programmer at any, at any organization who has like, you know, the key to all the protocols, the protobufs or whatever. All right. So unison wants to kind of revisit all of those assumptions from the ground up, and think about the sort of the big, you know, the big brain idea behind us is to think about the developer experience from the ground up for the 21st century. And the overarching non technical goal is to make programming delightful. And I want to say make programming delightful again, because I think that we, we kind of solved programming a single computer, pretty well. It's super fun. But once you start to do, you know, interacting with other developers, you know, developing for lots of like big distributed systems or programming for the enterprise or whatever. It starts to feel kind of like working in the salt mines. Unison again is early stages. It's come a long way. Since I started talking about this. Since I first joined up with with unison. It's full of rough edges and bugs and, you know, the developer experience isn't near where it could be and ought to be. But it's already great. And it's my favorite language to develop in at this moment. Although I do miss some Haskell features, which hopefully we can get in quite soon. The impression that I want to make is that unison has the potential to be completely amazing. And you can program in unison today. It works and you know you can write libraries, and you don't have to like wait for the future to happen you can just go and make it happen. And it's super easy. The barrier to entry is very, very low. You can just install unison. It's just a single binary that you get and then you just start coding in your favorite editor. It's a, and I'll show you how that how that works. So, what are the big ideas behind unison. The, the two big ideas which really are the same idea. Well, one facet of is that code is structured immutable data. It's not. So your code is not a text file. It is a database. And, you know, it's, it's an immutable data type, the code. And the other thing is that unison definitions are referenced by their hash. It's a 256 bit, sorry, 512 bit hash of their implementation. So they're not referenced by their names. So we talk, we say the code is content at the rest. So what does that mean. Well, so here we have what looks like two definitions. And they define the same function. So, you know, they do the same thing, but they, you know, maybe were developed by two different people or something. The structure of this code is, is identical. And the only thing that is different. So, you know, they're, they're, they're isomorphic up to alpha equivalents. They are the same except for the names. They have different parameter names, they have different names. And then different local variable names. But unison sees these two definitions as actually the same definition. Because when it, when it sees these things, it removes all the names, replaces them with the hashes of the reference of those names. And it removes all the local variable names and replaces them with basically indices, the brain indices. Every definition has a hash, which is a deterministic. I mean, is it determined by the it's computed from the contents. So it's a hash of the implementation. And then everything is referenced by hash as well. So actually this function have the action sort of under the hood looks like this. Instead of calling functions by name, it actually calls them by hash. And the hash is sort of like an address into a global immutable database that, you know, all programs share. So in the end, names stop mattering so much. And one of the things that falls out of this is that names start to be very fungible. You can think of, of unison types and functions as occupying this vast read only store, where each version of everything has a unique immutable address, which is the hashes definition. And the hash can have as many human readable names as you want. So that turns renaming into a trivial, non-breaking operation. And then reassigning a name. So giving a name a new definition is also trivial and doesn't break anybody's code. So in a traditional programming language, you will, you know, everything is referenced by name and the names can be sort of taken, right? So you have like data.list, for instance, like in Haskell. And like that means something. And not every program is going to agree on what that means. Like there might be different versions of data.list or whatever. And then if it changes, if the definition of the name changes, the dependencies might break if it's not like forward compatible or whatever. And then if a definition gets a new name, then the dependencies will definitely break because now they're referencing the old names and everyone has to rebuild and like change their code. In unison, this just doesn't happen. You can just change the names and everything's fine. Like I merged the pull request the other day, which was just like changing the name of fold left. Like instead of fold l, fold l, it was fold left. And like I just merged it, merged in the change of this very fundamental function in the base library. And nobody's code broke. It was totally fine. So hashes allow us to unambiguously communicate code, both across time and also across space over networks and memory boundaries and over time so across revisions of things. Cool. It also allows different versions to coexist. We also have no builds. So unison doesn't have builds like a traditional programming language. So why is that. Why does a programming language have a build like a, like, why does this happen. Well, the build ensures that, that all the code that that you're writing that you do want to build can address all the other code, whether that's on memory or on disk. And that, you know, that is pointing to the right, the code that you actually want to call is the thing that's being pointed to quite so that you know this is what linking does. And it makes sure that the names refer to the correct versions and this is what like, you know, like, library was called package management is doing. And then, you know, the compiler will like type check things for you if you have a type language. And if you have a test suite it will run your tests, like every time you run your build. And we just don't need to do that because everything is referenced by hash in this global eternal address space. And so everything is already the correct version, like the hash is unambiguous. There's no linking needs to take place, or the linking actually takes place like at development time. And then you can type check and sort of compile a hash once and then it never has to be compiled again. And if you have a test that, you know, to test some some definition of like a unit test or whatever, then you can run that unit test once and if it has if anyone has ever run that test on that hash, then you don't have to ever run it again. Okay, we also get rid of dependency covlets, because whereas in a traditional programming language, you know, you will have these build artifacts, like you run the built and you like generate some stuff, like, like a binary or class like jar file or something. The dependencies of your of your code are build artifacts, which are then referenced by like the language version and the package name and the version of the package. And then the different versions can't coexist normally, like without like some more advanced technology. Names are names are sort of taken. Like, you know, I was talking about like data dot list, for instance, like, oh, my library depends on my library depends on some version of data dot list. Another library that I depend on depends on a different version of that. And now I can't run my build because, well, there's a merge there's a dependency conflict. And this makes adding dependencies to programs a really big deal, because transitive dependencies might conflict. Sorry, was there a question. Oh, okay. Right, so transitive dependencies can introduce dependency conflicts. Okay, so contrast that with unison, where dependencies are as finely grained as possible. So every function has its own set of dependencies, which are just the hashes of the individual definitions. So you never have to like bring in an entire library if you don't want to, you can depend on just a single function. So the notion of like what a library is is very fungible. Like you can depend on two different versions of like the same type from some library, because they will have different hashes. And then so they'll be different types. And if you tried to pass one off as the other, you'll just get an ordinary type error. So instead of the sort of dependency conflict that comes from your, your package manager or whatever, you just get a type error, like in your programming language. Sorry. So I'm just getting over a cold here. Okay. So then for distributed systems is also brings in some another benefit, a huge benefit that falls out of this hashing thing is that we can do deployment just in time. So like, in a traditional programming language. Normally, everything is sort of designed around the fact that what a program is, is that it describes what a single OS process is doing. And then anything else is sort of described out of band by, by some other tech. Oh, sorry. Sorry, I'm just gonna have to mute myself for some. Okay, sorry about that. Zoom bar is in my way I cannot play my, oh, there it is. Great. Right so programs in normal, normal programming languages just talk about what a single OS process is doing. And then communication among processes happens it sort of out of band. And if you want to like call some, you know, you know, you want to call some other computer, talk to a program that's running somewhere else. That other location has to be running a program somehow. Like, that's not something you get to specify. But somehow it's running it, and then you send some bites across a socket or whatever. And then on the other side, hopefully, the right version of the thing is running. And then knows how to read your bites and like parse them into something sensible. And then it might actually run the code that you want to run. But, but it's, you know, that's not, that's not all that great because like everything described by all this sort of out of band tech. And, and that the whole sort of build deploy cycle also yet managed by more tech. Where the code is running is not something that you get to talk about in your code. And how the community or sort of what what data you want to send and what functions you want to call on the other side is something you don't really get to control except by this this sort of third party tech. In unison, instead, a program just describes the whole distributed system. And then to run the program is to deploy it. So there's no build. And the deployment itself is written in unison, you get to talk about locations of code as first class entities. So the assumption is that like, you'll have a bunch of nodes, they're all running unison. And the nodes will just communicate the hashes amongst themselves and send the unison code when necessary and everything sort of cashed at every level. So instead of like with RPCs, everything has to agree on the code, like in advance. And then you know you get to get you get to call a remote procedure using like a name. And then you're like, I don't know if we're broker or something. And then message passing is where like all the services has to have to agree on a protocol and there has to be like service discovery and stuff, and all of that stuff is done like not in your programming language. Or, you know, you might have this kind of like event bus, which is just like an appliance that you install and like you have a library to talk to it, or something. So in unison, you write your program with the, you know, there's a distributed API, and you get to talk about locations of other units and nodes, and you get to talk about what what functions you want to call on which locations and it all gets type checked and compiled by unison. So you'll have programs that effectively distribute themselves to remote locations. So the other big thing of this was that the code base is a database. So it's not, it's not a mutable collection of text files. It's an immutable data structure, and it stores your code in this commuter computable form. And then metadata like names and documentation and tests and things like that is sort of attached to the hashes. And the code base knows the whole dependency graph of every function. It knows how your code evolves over time so it has a history of every definition. And so it's a database and you can query it and you can manipulate it. And right now the implementation is literally a SQLite database. And so you can like, you know, ask you for the definition of something versus like here I'm in unison and I say, view list filter, and it gives me the definition of list filter. And in fact, I'm going to just show this to you instead of rambling about it on some slides. Do you just everybody wants to see unison. Let's see. Absolutely. Okay, great. Let's do that. So I'm on a Mac. So I can just say brew install. Unison language. And that should just install unison after updating, you know, my homebrew or whatever. Great. So now I should have a binary in my path, which is called UCM, which is the unison code base manager. Okay, so if I start that up. Okay, so now unison is running. It noticed that this is a fresh install. So it's actually downloading the base library for me. That won't take long at all. There's a lot of code in there. So it's not, it's not like super fast. Okay, so here I am in my, in my unison code base manager. The unison tool allows you to manage your code base. So your code base is no longer a collection of mutable text files. It's here in this, in this database. So I'm in my, in the root of my namespace and I can see what's in here. So I have this base namespace, which unison has installed for me helpfully, helpfully. And if I look inside of that, I can see that there's a bunch of stuff in here. For instance, there's, I think there's So I can see the internet. See what's in here and I can see the list. Is it data. No. List. This back. It's just under list. Great. So if I look under list, I can see that there's a bunch of operations on this. And you can see, you know it has the names of the operations and it has the type of the operations. And there'll be more stuff under, like, there's a type called non empty to the non empty list. And then there's sort of a folder under here, a namespace non empty, which will have functions on my list. And like, there's a function called all, which takes an A to a Boolean with some effect E, and it will take a list of ways and turn that into a Boolean. Right. If the predicate is true for all days in the list, and it'll have some effect, some effect D. So this is a effect. This is called ability. Notation. So the functions come with these algebraic effects, which we're calling abilities. We'll go into that in a, in a moment. But I want to show you was that I can, you know, view this filter. It'll just give me the definition, nicely sort of format it. If my, I think if my, yeah, so it'll try to like format it to fit the screen and stuff. That's, that's pretty great. I can ask for the dependence of filter. This is, and I can see all the functions that call this filter. So the whole dependency graph is stored. Here. What else? Get dependencies as well. And that's just like Boolean lists. Great. To interact with this. Right. So if you want to do more than just like manage your code base. And there's a bunch of stuff you can type help. And I'll tell you like all the cool stuff you can do in here. So what, what do I want to do? So if I say, Vim dot resist, just call it scratch that you say. So my other screen, here it is. So now I have a text file and then, and if I edit this file, since since I'm editing a file with extension dot you in the same directory that I started in UCM and so in my UCM working directory. If I edit a file, it will get picked up by UCM. So if I start a line with a greater than I can just type units of expressions. So like, let's do a six. So that's great. Or I can say it's not filter is even for great. And it has this feature where anything that's below a triple dash. So a line that starts with three dashes or more. Anything that's below that line is a comment. So it'll get ignored by unison. And so the way I normally work is that, you know, I'm working on something and then I just hit my hit a little hockey and it'll put everything sort of below the fold, everything. And it's a nice way of nice way of working. So in practice, you end up having just one file that you're working in, just sort of like your notepad or scratch base. And then everything else. I mean, you'll do everything in there. So we can write a definition. If you just write a definition like all times two of x, six times two. Great. So now it's just like, okay, I have, I have found this definition. So all I did was save the file. So save the file and it gets picked up by UCM. And it's saying, great, I found this new definition that you can add that if you want. I'm going to add it in like scratch. It's just like little play space. And I type add. And it's saying, okay, well, I added these definitions of times two. And I can say, well, show it to me. And say, well, here it is. Okay, it's a little different. It's not exactly the same as I wrote it. But the cool thing is that I can just get rid of the source code now. And you know, hold on to the, the code for me, and it can generate source code for me whenever I want. And put it in my scratch file. There. So what else you can find stuff that was just can be handy. So I want to like find so anything with a name list in it, or find anything of type, you know, list of a to a is this. Yes, unsafe that takes a natural number. Usually takes a list of a usually they might crash. But the other way. Right. So you can do have type based search. If you're a Haskell or that's basically like Google, which is in a very similar way. But this is just one way of interacting with us. You can there's also a user interface for this so you can say UI, and that'll open my your local units and code base in browser. So you can tell us there's a sort of bar here on the left. So the base library is here. And so we can open a type like oh, here's bag, great. And it'll show you the documentation for bags. Which I can also get in UCM, like I can say docs bag. And render that to the console. But in the in the UI it's much nicer to look at and everything's hyperlinked. So, you know, I can say, well back to single case okay great so let's back that okay back that single then I can get the docs and the definition of back that singleton just by clicking on it. And then these examples here. So just showing an example for from that to construct a back bag given a map keys to counts. This is a live. This is like a live example so it's being evaluated here. So the doc. The documentation here for bag is actually a unison expression. So documentation is written in unison. And it includes the ability to sort of transclude unison code and have it be evaluated when it's being rendered by the tooling like UCM or only UI. So that's super nice. So you can write this nice. And I think, honestly, I think like the documentation is like worth the price of admission by itself for for unison. Because like you can write this super nice documentation where you can like experiment with the stuff that you're documenting sort of in line. Like this text is not stored anywhere this is an actual program being evaluated. And what's cool is that, like, if the name of backed up from text changes then this talk changes as well. If the definition changes and gets like updated, and this gets updated to the new version of it as well. So that's, that's super cool. How much time we have left. As much time as you can take. Okay. Yeah, our one of 18. Like, like, there have been people that stuck around in conversation and that in this group until one o'clock. So, yeah, I want to say I'm happy to stick around as long as you want, but one o'clock your time is too. Yeah. You're sounding ill so happy you made it you made it here tonight, sir. So yeah. I just I should just that's off plane so that's another thing. Great. So, I'm thinking we can just like do so we can either like do a little unison programming, or you can talk a little bit about the distributed stuff. What do you think I the distributed stuff is is way cool. I discovered that in some of your talks previously but I know like anybody here that hasn't had any exposure to unison would would definitely kind of kind of, you know, make your eyes go a little cross for a minute and then, you know, all right. Yeah, that's I do have one. I do have one question for you. And it's been bugging me for a while. There's records for example. How are you doing the same thing. In that, like, the names are getting maps to to dictionary entries and the, and the, and the structure itself is becoming a hash or how is that yes. Yes, we are. I mean that's that's actually program or specified. So if I go back to my scratch file. So I can say. Type, let's say I need to say, so if I just a type, it'll give me an error. So I need to specify. I can make a structural type. Let's say start to type maybe a is just a or nothing. Okay. So it's okay I found this, and you can add it. And I'm like, oh great great I'm gonna add it. Names of maybe. That's weird. I thought I already had this. Oh, yeah, there it is. Oh yeah okay because I'm not at the root. If I say names of maybe it'll say like okay well this type is also called based on optional. Okay. It's, it's that your scratch dot maybe. It shows me that same type again. They are the same type. Like, they're not. They're just different names with the same type. So they're not like different definitions in any, in any way. In fact, I can even do think I can even do this. You can add this but it's also called scratch maybe base option. And if I'm already in scratch, and I save this. It's like, okay, this has already been added. There's nothing to do here. So does that answer your question. Oh wait, the other thing was, the other thing was like, okay I want to say unique type. Email address, which is an email address containing a text. It's a little bit different. So here like, I do not want texts and email addresses to be the same in any way. So I'm creating a new unique type, which is not going to get confused with any other type. So that doesn't get hashed or does is it is it gets hashed with with a with a grid sort of salt. And so it makes it so that this actually, if I add this, I can actually add it again with a different hash, if I am not like, if I'm in a different namespace or something. Okay. Yeah. Awesome. All right. Oh yeah, how do you run the program looks like that got answered. Yeah, running programs is in the docs. Oh yeah, the website super nice. So if you just go to the unison dash link dot org, the super nice website with like examples and these these examples are also like live evaluated. This whole website is a unison program. So like, this is this is a doc in unison, which is an actual type. So if you say, Well, let's do it in the UI. See, There's this is a shared space quote shared that you didn't like that link that work, which has a bunch of libraries already on it, including base, which you can access, you know, just sort of over the interwebs. And so if you go to base dot should be just here doc. Doc is a is a type in unison. And unison documentation doc is a computable first class documentation you are reading a doc at this very moment. And there's a tutorial link to documenting your code. So the docs are written by, you know, you sort of doc blocks, but a doc block is is just a unison expression. And it has like pretty rich. syntax for doing all kinds of cool stuff and you can call out to unison code inside of your docs. And like you can ask for the signature of a function and it will render it inside the doc. All kinds of cool stuff. Like to me like that alone is like worth the price of admission. Like without all this stupid stuff is unison built on top of Haskell. Yes unison. And the type checker and the runtime are all written in Haskell. What is the thing I was going to do. Oh yeah, I was going to show you the distributed stuff. Okay. So here's a function that takes a list of natural numbers. Nats in unison is the type of 64 bit unsigned integers. So it takes list of those. And it does something with them to compute a single answer. And the use thing is like an import statement is just like okay use plus equal to mod from the net namespace. And then it's a like okay I want to map over the sequence, adding one to every element. I want to filter, keeping only the elements are divisible by seven after adding one. And then I want to sum them all together. All right, so pretty straightforward little function. This is a local fold map or map reduce on a list. So there's nothing distributed or remote happening here at all. This is just an ordinary function on a list. Right at once every element retain only result divisible by seven and add up all the results. Okay so now we're going to move that to a distributed execution. So now we have to like how do we do that. Well typically there's a huge increase in complexity. So we have to move away from the seven lines of code that any programmer could write in 10 minutes to this huge multimillion line framework like how to or spark or whatever. And you have to read a book that 600 pages long. It's like, you know, we might have to get a spark certified or, or whatever, like, just setting up an administering a spark or how do clusters is not no joke. Like it's a complicated enough thing to manage that there's literally a job you can have which is had to administrator. And more than that, there's a whole industry, which is dedicated specifically to figuring out how to take these seven lines of code and running them on lots of computers on very big lists. Right. It seems crazy. So, again, local map reduce on on a list. And so this is this unison code right. So then I want to show you the distributed version of this that does is on a distributed list over, you know, potentially millions of notes. There it is. Right. So it's like, not that different. And that's like the whole, the whole point of this. So things that change with like, there's a different data type here it's no longer just a list it's not an in memory list it's a distributed sequence of natural numbers that uses some kind of like partitioning key K or whatever. It, it takes up this remote ability, which is saying that this function uses the ability to like remote stuff. That's simply by the by the fact that it operates on this distributed sequence type. And so you can just map over it, like you did before filter out, you know, elements you don't want and then summit. And this will just sort of like, you know, I don't say like magically happen. But wherever that sequence is living. We will, we will send the computation that needs to happen at the partitions of the sequence, like they're living on like S3 somewhere in the in in AWS or, you know, they're like on disk on some unison note somewhere. And so then what this, what this will do is it'll take the like this value DC DC will like know where where it is. And it will send the functions, the computation that needs to happen over the portions of the sequence that live at those places and ask those nodes to perform those operations. Okay, so we move the computation to the data, rather than moving the data to the competition. And this is again like super straightforward to do because it's super straightforward. Lots of lots of lots of nuance there and lots of difficult implementation details, but conceptually it's very simple. We we address everything by hash. So we simply just tell the remote location here the hashes I want to run. And then we figure out how to make them know what those hashes refer to. And I think that's like all I have on that. The distributor stuff. The. Let's see. No, actually. Okay. So the remote ability is sort of based around these operations. These two primitives fork at takes a location and the delayed computation. So this sort of tick thing here that apostrophe means that this is this is delayed. This is an unvaluated thunk or computation that gets passed into here. So it's some some computation that ultimately returns a value of type T and can have these effects or can request to use these abilities, G exception and remote. And then the whole thing gets turned into a task with a T in it in the remote ability. So you can say, what you're saying is basically take this computation fork was like spawn a new process at this location. And you'll note that the location comes with the type parameter G and G controls the capabilities of the location. And that could be something like this gases, or it could be something like talking to S3 or it could be something like talking into a quantum computer or a GPU or something like that. Lots of different stuff that you could have like different locations with different abilities. It's not what's actually running there. Okay. The cool thing is that this computation will just get hashed. And then the location that location will just get asked by the runtime will just get asked. Hey, run this hash. And then a way you can take a task that you constructed with fork at and you can ask to wait for it to complete. And you'll get the result back from the, from whatever location is running it. And we can actually just look at the share to go. If you're curious about the distributed stuff. There's a unison dot distributed namespace, which has a fair documentation and talks you through writing some of these distributed distributed computations. So right now the only thing that ships with this is a local interpreter. So if it doesn't actually do anything distributed, it will just like sort of simulate lots of locations on your computer. But, you know, we are that there already exists implementations that are there exists an implementation that that runs it in the cloud. But we're not ready to share that just yet. Let's see. Yeah, stop by the distributed channels like you want to chat about this to get help. There's we have like a series series of tutorials on this thing here to go to the, to the blog, it's the blog. Be learned. There's been a couple of questions in the, in the, in the chat in the chat. Okay. Yeah. Will you want us to get slower over time as the number of hashes increases. Yes, the answer is yes, as your code base gets bigger. You know, the answer to that is, as your SQLite database gets bigger. The queries will get slower. But that's just like, you know, that's just like a basic fact of software engineering like as your code code base gets bigger your, your build times get longer. But the thing is that you'll, you're never going to be like waiting for a unison built. Like that's never going to happen. So like what does it mean for unison to get slower. I mean the program running programs are not going to get slower. But like the unison code base manager will get slower like as you have more stuff that it's managing, possibly, because like the indexes will get bigger and stuff. But I it's not there's nothing we can't like overcome and also like you probably shouldn't have like the entire universe of unison code in your code base. So you can't just generate all valid unison and have all that possible ashes. I mean, yeah, that's like the ideal right. That would be, that would be awesome. Because just have a fun. Hey, yo, I know you just have a function that takes the 512 bit shot and just like, you know, casually determines what the, what the value was that get that generated the hash. That's how we get. Do we have category theory idioms, functors, monads and applicatives. Okay, so the ability stuff is monads. You can, you can think of that as, as being a free monad. Or, yeah, a free closely category. But So there's not in base currently a functor or monad or or applicative like type. At this moment, but there's there's no reason you couldn't write those like that. That's absolutely like we have higher kind of types and so you can absolutely write them. However, you may not need to. In practice, you end up using these abilities was composed quite nicely. So I can talk about that. Great. Abilities. Also known as algebraic effects in other, in other circles. Okay, so abilities are declared using the ability keyword, and you can say ability abort where and then you give the constructors of the ability, these are very much like GDTs or, you know, generalized algebraic data types. And then you have. So abort will actually create a value of type T with that request the abort ability so we'll have this sort of squiggly, squiggly line. I mean the squiggly bracket abort. If you call, if you actually call the board. Right so this thing here is actually constructing a request for a boarding. And then here I have a definition that actually uses it. So I'm saying, okay, head takes a list of ways, using me and a but may request to abort. And if it's so if it's empty, if the head of the list is empty, if the list has no head, this is empty and then it's going to request to abort. Okay. And on the other side of that, there's going to be a handler, which will, which will interpret what it means to abort. So here I have a handler, which will take a computation. So it has this sort of apostrophe here which means that this is an un-evaluated thunk that generates an A and may request to abort. And I'm going to say handle forcing P. So the bang means force force this thunk that strictly evaluate it right now. And then pattern match on it. If it called if it is the abort constructor, then we're going to return none. If it doesn't, if it returns the A without calling any constructors, then we're going to return that A. This is kind of a weird syntax, but, but this pattern here is saying that this is going to be an ability constructor. And the ability constructor is on the left side of the arrow, along with any arguments to the constructor. And on the right side of the arrow is going to be a function, which is the continuation of the program. So you can kind of think of this as exceptions. So here, this is like throwing an abort exception, basically. And then here in the handler, I'm saying like, okay, catch that exception. And if it's an abort exception, return none. But the difference between the difference between exceptions and abilities is that abilities come with a function that you can call to resume the program. That's the continuation of the program. I'll show you that here in a minute. But, you know, this is ignoring that. So it's just calling it underscore and not using it. So this is working as if it were an exception. I have a couple of questions. So, if I'm understanding with correctly what you're doing here. So essentially, positively defining within the syntax of the language itself. A thing that is usually built into the language and works outside of the actual syntactic structure or the regular syntax structure. So a function is called either it does some, it returns some value or it throws an error which kind of happens outside of the flow of the program regularly. And many languages. You're actually defined. You're actually defining it within the structure of language here. Sure. Yes. But so in Haskell, for instance, and in many, many functional languages, you'll have something like optional or maybe or whatever, which will also allow you to do this. Right. But the difference really is that abilities don't come with a syntactic overhead of, you know, monadic composition, composition. So you don't have to have like a do notation or a for comprehension or anything like that. The code will end up looking like, like straight line side effecting code, even though it's actually monadic. And we'll look at that here and in an example of a state machine. So here I have the ability called I'm calling state in the base library. This thing is called store. So you can put something in the store and you can get something from the store. I just I'm just calling it state for reasons names don't matter in unison. You can rename it whenever you want. So I had this ability and has two operations on it. I can put an S into the store, which returns unit like it doesn't actually give me any value. So it just says, okay, I did it. And then I can get the S out of the store, which will just return me the S. I can write a little, little helper, you know, little, little functions for a stack machine where I can pop from the stack. If I have a list of A's in my state. Then I can get an A out of it. If I want to abort, if the stack is empty, because I'm actually calling head, going head stack and remember head calls abort. Right. So if the head is empty, I mean, if the stack is empty, then it will abort. Otherwise, you'll get me the top of the stack. Like saying, and you notice that this is now looking a lot like just an imperative program. So saying, well, pop is let stack the state I get. And then put drop one stack. So take the head, take, you know, remove the head from the stack. Put that in the state. Right. We're moving, we're moving one element, and then return head of the stack. So it looks like an imperative program, whereas actually a purely functional one. So then we can, we can push onto the stack. If we have a stack in our state. So given an A, I can say put into my store. Whatever state I get gives me with the A on the front of it. So cons puts an element on the front of a list. So you'll note that here I don't have to say like, let or do or for or anything like that. I could just straight up compose functions. And say like, put the cons of the A in the state that get recall. And then I can write a little adder, or I can say to add is to push pop plus pop. Great. So my handler for running my state machine will take an initial state of type s. It'll take a computation, which I'm going C of type a, which may request to use some state of type s, and have some other effect the end it'll sort of handle the state as effect, leaving only the effect on handled. And then I can go on to maybe other handlers. All right, so then the body of that function is just handle forcing see with each of us, where each of us is the handler. And that is going to match on the, the E argument, which is the actual request. And it's going to say, well, if it's a state that get with continuation K, that's the rest of the program. And then I want to continue the program by calling K of s, but passing my the state, the current state to the continuation. And because you know I'm asking to get the state. So okay, here's the state past that to the continuation. But notice I'm actually recursively handling that with each of us. So I'm handling the rest of the program with the same handler. I could, if I wanted to switch handlers here, or do something else. All right, so this has a lot of flexibility. So this is like I'm catching the, you know, the program is throwing an exception to get the state. And I'm catching that exception. But then with the exception I also get the rest of the program. And I'm just saying like okay well here go go run again with this new with this is a value s you got from the store. And then if it's a put with a K, then I just pass unit, I say like okay I put the state. And I call the handler with the new state s, which I got from state output. And if it's an a, then we're done. Cool. So, normally, when you're like writing application code, you're not actually running, you're not writing these handlers very much, but you will be writing code that looks like a lot like this. I'm not using the, the abilities, but if you're defining your own abilities and stuff you'll be writing handlers like this. And then in the end I can run my machine by saying like run state with the initial state being the empty list. And now I say like okay. This is now this is an undervalued it. The tick let opens a block like this. So then I can say, make this be undervalued and pass it to run state, which will force it. And what that computation is going to do is push for push three, and then add them. And then we'll return seven. Oh, actually this is, this is wrong, you should, they should be, there should be a get at the end. This is this slide just generated from an older version of this code. Anyway. Anyway, getting the state again after the adult version should be seven. Cool. And then, oh yeah, here's this remote thing again. And that works very much the same way like it's not magic built in anything remote is. It's just an ability. It's somewhat complicated, but it's just another unit and ability. That's what I'm going to find in unison. Okay, let me see if I can get some of these questions. Do you have any examples of refactoring cat wrap my head around how say a new improved implementation of this sort might propagate through a code base. That's a really good question. So the way that works is that the unison code base manager knows the whole dependency tree. So if I am for instance in. Let's see. I want to know, develop so so let's say I want to be in depth. Okay, depth. fork base dot dot is root so fork the base names from the root and call it my base, whatever. So now I have a fork of my base that I'm just going to start working on CD in there. I have all of base in here. This is not another copy is just a reference to it. And now I'm going to switch to my scratch file and define a new version of sort. It's not sort. Oh, there's no list of sort. So bye. Okay, great. Great. Find sort heap that sort. Okay, so it's a heap sort. Okay. Is that going to be super complicated? No, sort descending. Oh, okay, so here I have heat that sort great. Are there dependence on heat that sort. Yes, a whole bunch. Fantastic. So now I'm actually going to take heat that sort and I'm going to change the definition. Okay. Now it's going to do ascending. Doesn't know what sort of sending means. So ascending. No. There's sort. This ending. Not sort. We had it. Max is there heat up in. No. Well, okay. That didn't work. But let's just do the sort. Descending and not reverse. That's not good. Great. These names already exist. You can update them to your new definition. Why thank you. I will do that. I've updated these names to your new definition heap that sort. I added some data. It simply means that I can say. It shows me that I actually wrote this function. And in case of a license. I have. The documentation shows you how to do that. You can set up like a author name and. You bought license for your code and stuff. So I've changed this definition. Refactor base. So that sort now works in the other direction. How did that happen? Well, it happens. By updating all of these dependents. Transitively and then updating their dependence, et cetera. And I can actually ask, is there anything left to do? No, there's not. No conflicts in progress. It was able to do that update just fine. So now sort in my base. It now works the other way. That's really cool. I was the one who asked the question, but. I think I get it. That's awesome. I really like it. I feel personally attacked. I write a lot of code that I, you know, trying to emphasize immutability and then all my code bases are completely mutable. Right. Right. Yeah, we're like, Oh, it's all immutable. And then, you know, code bases are mutable bags of text files. And it's like, you know, our. We build this sort of these like nice little universes, but then the tools that we use to build the universe is like the same pickaxes we use in the salt mines. It's terrible. I can go on about that. Let's see. I like the idea of code. Not sure I like the idea of code as immutable data. Well, if I can't sell you an immutability and like, you're probably in the right group here. Functional programming. Like you, you know, the rest of. Rest of the people here can probably sell you an immutability. I think John was saying he doesn't want his regrets. I don't want to be cast in amber. Oh, I see what you mean. Like, you don't want the whole history of everything available forever. Well, okay. Well, I mean, you can take that up with gifts. Like everything you've ever done wrong is kept forever by GitHub. As long as you like shared it with someone else. But your history is all available here and it's like editable and stuff. So if I go into history of my place, I can see that. Okay. I updated. So this, this is adding my author and license to the definition that I updated, I think. But this, you can see that it, these all got updated here in the history. And, you know, if you don't want to share that, if you don't want to like update heap sort or whatever, you can always go back to like, I don't know, I don't know. Nevermind fork five to. Dev. Nevermind. Dev. So nevermind. So we're here. Great. Diff.name space. Base with nevermind. They're identical. Right. So now I'm, I'm back to not having done those changes. Great. So you can just go back in your history and say you can take any of these hashes or by number like this and you can say fork to like check out a fresh copy of that point in history. So, so that's really another thing. The, the history is all managed by, by unison. Right. So like, you cannot use get with this at all. Which, you know, you may think is a, is kind of a downside, but it also could kind of be an upside. So we can. And we're building something that I think is going to be a lot better than get. Because, you know, the user code base manager understands the whole structure of the code. And so we can. The potential upside of like abandoning. Tech space tools is huge. And I think hopefully we're going to see some of that this year. With some new tools for, for unison. So you talked about the distributing computation. How does that, how would that work? Like. You know, Is the expectation that it's going to be run unison or that unison will be running directly on the hardware. Or that it will be running a container that it will be running. In a virtual machine. Yeah. And you know, the above really. So we're currently working on a. Native, a native compiler. For unison. So you, you know, you'll just. You know, you can, you could. In theory. Be running unison on, you know, Linus container somewhere in the cloud. Or, you know, you could. You could use. Unison cloud, which is something that we're building. So we'll just have a. Cloud. Provider platform where you just get an API key. And the library. From unison computing. So we'll just like spawn. Unison nodes as many as you want. And we'll like, you know, basically charge you for the AWS or, or. Or Azure. We'll pass our Azure bill on to you basically with like a tiny, tiny bit of overhead. So that's, yeah, that's what we're building at the moment. We're trying to get. A cloud based. Like a cloud service for running your unison. Programs. And it's going to be like, it's going to be super crazy. Delightful. Like I've seen. Demo's of this. And it's just like. It's ridiculously cool. I can't wait until we're actually like ready to share it with the world. But it's just like, you just write your code in your scratch file. And like, it's running in the cloud. You know, when you save it, it's just. Ridiculously crazy. So the developers are essentially. Connected up to the cloud in a way. They're, they're. Whenever they write something into their local database, it kind of. Distributes or. Well. Well, you have to like run. It's a program that you write. You add it to your code base and then you run it. And then the program being run is the thing that actually goes and distributes it because it's like talking to our servers using your API key or whatever. And it's sending your code. Up to our servers. And then running there. And if we've seen your code before, then that's a no up. So you can just like. You know, your, your build might be very, very short. In, in. So. Yeah, I haven't seen that run. I think that's just like, it was. Demo is just like completely my bullet. It's like even easier than like pushing code to get. To get. Oh, that's. That is, that is not as much of a brag as it would seem. Cause. Get is often a pain in the ass. Oh yeah, that's true. That's true. And like hit history will always be a pain in the ass. Like even in unison, I think. But, you know, it's not going to be as much as a purple pain in the ass because like dependencies are all like. As finally getting as possible. The tool like understands the structure of the code. Stuff like that. Ah, what, at what level is the code hashing is the code. I write hashed or is a normalized form hashed. Um, it's actually a normalized. Um, Form somewhat. Well, what gets hashed is, I believe it's called the A normal form of the, of the code you write. So it's essentially the same, but it might have like import statements added and stuff. Um, I think I might, I think I might have that wrong. It's mostly the code that you wrote, but when it gets rendered back to you, it might not look like what you said. Also, we ignore the names. Sometimes. We try to keep around the names of local variables and stuff that you wrote. And that's all cool. But if somebody writes like the same function with different local variable names, then we're just going to say like, hey, this already exists and your names are, are out. Uh, and like, sometimes you might write a function that you call it something. It already exists with a different name. And you just like add the name, but when you see it again, it might have this totally different name depending on what name space you're in. So we always try to find like the, the shortest, unambiguous suffix of a name to like, to show you a nice name for something. But does that answer the question at what level is the code hashing? Yeah, it is. It is hashing the code that you wrote. So, uh, do you find yourself when trying to capture some business logic, uh, type, uh, type problem, uh, writing a function that you later learn has already been written. No, that's like almost exclusively in library code. And that's happened before, like, yeah, this happens many times when working on like base libraries and working on. It's like the more abstract the thing is, the more likely it is to happen. Like, if you're working with concrete things like business logic, then it's very unlikely that you'll, that you'll write the same function twice. But even so, like, you know, you may, the hashing is, the hashing is not a de-duplication mechanism, right? That's not the primary function of it. Uh, it's, it's a global address space to make definitions unambiguous. And so, and also to allow them to coexist. So with business logic, it's like, it's very often the case that you want to have multiple versions of things living in your code base at the same time. And that can be a huge pain. When you have like, you know, wire formats that evolve over time. And like a version of the server will have to talk, talk to all the clients. You know, they'll come before and stuff like that. So if you're, if you're writing unison program. With a, say a web front end for some other front end. How is it generally, are you, are you really just writing APIs in unison or. Are you, are you know, are you potentially extend that into the, into the display format? Wait, can you ask a question again about, was this about web front end? Yeah. So, so are you primarily writing API, you know, surface area with, with unison and doing some other JavaScript or, or HTML or et cetera, et cetera. Right. Yeah. No. So it's at the moment it's not well suited to front end development. So I would advise if you want to use like unison on the back end, you would should definitely be using something else on the, on the front end. And that's mainly because like there aren't libraries and also like, we don't compile the JavaScript at this moment. But that may all change. So that'd be super cool. But I mean, we're running our website on unison. So that's cool. But like literally running in unison. It's actually just like generating it once and then serving a cashed, because it's all, it like doesn't change. It's not interactive in any way. But this whole thing is a whole thing is a unison document. So can I ask a stupid question? This might be just my misunderstanding of the way things are stored. But if all the code seems like it's sort of mirrored. I mean, I mean, it feels like it's probably more secure than get in a sense, since every individual function is hashed. But if I were to try to convince. My boss, like five years down the road. That we can put code in here. And, you know, other people aren't going to necessarily be able to see like connection strings or secrets or things like that. Is that. It seems like it would be in some ways it seems like it could be more secure than get in a lot of ways. Like if I check in a secret to get by mistake. You know, someone with the right password could get to it. But in this case, everything is hashed. Potentially stored in a database where. You know, if no one has access to. I don't know, the string littler literals or whatever it only can see the hashes in the database. Oh, excuse me. Now. If someone has access to your code and you like. If someone can see your code. And somebody, and you have put your secret in the code. They can see your secret. That's just, that's just how it is. Yeah. But we don't really do anything to like prevent you. You know, doing that. Because like. You know, you can put a text ring. Text ring in your code and you like accidentally share it too. So, you know, you can share code to. Unison share. Let's say you had a library that you were sharing. And you got indexed. You know, over here, like, oh, let's say Chris. Penner accidentally put like his. Get a password in here. I see. There's nothing we can do about that. But for example, you know, you know, you know, you know, you know, there's nothing we can do about that. But for example, if I have, if I, essentially, I could have the code stored locally. And it's not. I mean, essentially it sounded like when the code is, is quote unquote building, it's. Checking hashes on the server to see if something has already been hashed before. Oh, I see what you mean. Oh, so yeah. So if you're running on like the unison cloud. Yes. Yeah. So then. You know, you, you could. Yeah. I mean, you could definitely work it out so that you're never actually sending any secrets over the wire. Okay. So that, you know, it's, you wouldn't like ask us to talk to your, you know, Postgres database. Yeah, I guess, I guess, you know, if I put like a secret somehow in, in code that I didn't expect, you know, I might have, you know, a local test harness or something like that. I wouldn't necessarily want it so that. If that secret got to. If I were using the unison cloud. I wouldn't want it to sort of be publicly available in a database, but it sounds like that's not really the case. Really, I'm just thinking of ways that I can convince my boss to use this in the future. I think it's really, oh yeah. Okay. It's, you know, it's going to be awesome. I think that's really the angle you should take. Okay. It's, you know, it's not going to like increase. KPI's or whatever. I don't know. But then the, yeah, the main reason that we're, we're building innocent. And I think that what's going to like convince bosses is that the, the current way of writing distributed systems. Just sucks. And it is very, very expensive. And so we want to. Make that not, not just not suck, but make it completely delightful. And put that within the reach of a single developer. Which, you know, translates to cheap. So maybe your boss like that. Yeah. No, it's, I really like it. I think it's great. Great. Great. What else? It's now. An hour and a half. Do we want to stop here? Yeah, that's, that's your call. We usually, after the, after the end of the talk. You know, we'll stick around for some people will stick around for discussion. You know, And it just becomes a general conversation. So if you're at the end of your material, we can stop the recording. We can stop the recording. We can stop the recording. So if you're at the end of your material, we can stop the recording and begin with that. Great. All right.