 Hi, everyone. Thanks for coming to this talk. So my name is Anupam Jain, and I'm going to be talking about purely functional user interfaces. Some background about me, I work as a web developer. I build websites for financial products, and we use functional programming for that. So as you can imagine, I have experience building user interfaces with functional programming. So this talk is like a distillation of my broad experiences building those user interfaces. And one of my aims is to show you existing solutions and how they don't quite match up in my experience, and then show you how we can do things better. So this is an overview of what I'm going to do. One of the things that I think a lot about is how to make the task of building user interfaces better. So it's not just purely functional user interfaces. It's about purely functional user interfaces that scale. So let's take a moment to define what scale means here. The easiest thing to do is to make a solution or library simple. When you have a problem, you can come up with a simple solution. That's the easy thing to do. But that doesn't always work, because when the problem statement changes or your requirements change and they will change at some point, then because your solution was so overfitted to the problem, you end up bumping against the edges of that. Or your solution will work only for some specific use cases, or it will not work when you have a more complex problem in the same vertical slice, but more complex. So it doesn't work. So I built a library called Conquer that I hope scales properly. So you can define it for one specific. So you can use it for one specific use case. And I hope to show that it can adapt easily to changing requirements and changing complexities. So that's what the talk is going to be about. Basically two parts to the talk, which is an overview of the existing UI landscape and the Conquer UI library. So this is the guiding principle behind Conquer. How do you make things scale? There are basic tool sets that you need to provide to the users of your library. And it's best if those tool sets are minimal. You don't want to have 10 different tools for 10 different use cases. You want to provide a handful of tools for a lot of different use cases. And they should be orthogonal. So you can combine them, mix and match tools to solve a huge variety of problems. So I've tried to adhere to this principle. I try to remove things from Conquer more than add things to it. So yeah. And just to give you a quick example of scalability. So scalability on one end would be that is it easy to write a Hello World program in Conquer? So this is slightly better than a Hello World program. The Hello World program in Conquer would just be text, hello sailor. So you just display some text on the UI. And this basically wraps it in a button. It's a very simple declarative code. I hope everyone can understand that. And what it does is it shows a button. By the way, this entire presentation is a Conquer application running in my web browser. So I can show you live running widgets. And on the other, not really on the other end, but one of the more complex things that you can do is build a to-do list. That's the benchmark test for any UI library. So this is a running to-do list application where you can add does. And you can edit them by double clicking. And you can mark them as complete. And you can delete them, and so on. And you can obviously filter them. But I don't show the code for that. That's also pretty simple, but it's not here. And the entire code to do that, except for the filtering, is literally this, 18 lines, including spaces and everything. And I want to emphasize here that this is idiomatic code. So this is not some fancy HTML code golf kind of a thing. So this is how you would normally write applications in Conquer. And that's what I mean when I say it scales. To-do list is not a very complex application. If you had to define its functionality, you can define it in a paragraph. So the code for it should not be two pages long. So that's what Conquer tries to do. And obviously, this code will not make a lot of sense to you right now, but hopefully at the end of the talk it will. And please feel free to ask me any questions any time, because just me going through features and syntax is going to get boring. So if you have any questions, especially I'm not an expert in things like React or any other user interface libraries. So if you think that you know of a framework that can do things better, just feel free to stop me and tell me. And I'll be happy to know that. And I'll try to improve Conquer. OK, so yeah. And if you really wanted to play code golf, this is the same code. You can compress it down to a tweet. I tweeted this out sometime back. So you can actually implement to-do MVC in a tweet. And yeah, so let's start with the existing UI landscape. We're going to go slightly back in time. So we're going to think about how UI definition is a difficult problem. So if you think of UI, it's really two things. It's a user interface. So the user provides some input. You allow the user to provide some input, usually through some input hardware. And you use that input to perform some calculation, which is independent of the user interface. And then you provide feedback to the user, generally by drawing lines on some kind of a display device. So it's really simple. And if we wanted to just write an API for exactly this, just have a function called to accept input, have a function called to write something to the display, then what would happen? So this is how things used to work. You had direct access to the rendering surface. So you can draw a square there. You can write some text there. And the rendering surface was persistent. So you can write something. And it will show up on the display device. And then next frame also, unless you change something, the same thing will keep on displaying. So this is a very simple declarative way of handling rendering stuff. What this doesn't take into account is that, so this is an example. So it's easy to draw a circle. But it doesn't take into account how you respond to user input or events from outside the system. So a simple thing would be that you wanted to animate this circle in a particular direction. So you would have to do something like this. And the way generally things happen is that you have some kind of a callback where every second the callback will be fired. And then you have to update the state of the circle on the screen. You have access to the direct rendering interface. So you can just change the position of the ball on the screen. Some complication arises here because you have to erase the previous position. It's all persistent. So you have to erase the previous circle. And then you have to draw it in the new place. And that can get complicated because erasing means replacing it with a background. So you have to keep track of what the background was before you drew a ball on top of the surface. So it gets slightly complicated here. What people came up with is instead of updating just the position of the ball, at every frame, just redraw the entire screen. That's much easier to keep track of. And then you have some kind of a state function which keeps track of the position of the circle. So that's basically immediate mode, where you have a state with the position of the circle. And then every frame you draw the entire background and then the entire whatever objects you have on screen directly there. So this is immediate mode, where you have a rendering function that renders the entire screen in one go, every frame. And you have callbacks that change the state. So this is how it was for quite a long time. And then people had to complicate it. So they came up with this thing called retain mode. Now why do we need retain mode? So when we are thinking about a single circle on the screen, it's very easy. It looks totally uncomplicated. You don't think that something could go wrong with this. But what if you had 10 different circles on the screen, all moving in different directions? And you have callbacks changing the positions of arbitrary circles there. And if you wanted to, on every frame, draw all the 10 circles, then you would have to remember the circles that did not change and then change only the things that did change. So you have to keep track of things that did not change also. So what retain mode does is that it manages a tree of objects for you, where you can only change the thing that changed. And then you can just draw the tree as is. So it's basically an extra layer of state management. And now we're back to the persistent thing that we had earlier, where this is a higher level thing. This is at the tree level rather than a pixel level. So you're not persisting pixels. You're persisting an entire tree. And then you change only one part of the tree. And the entire thing can be redrawn every frame. So we started with the persistent pixels. We moved on to just refreshing the entire set of pixels. And then we're back to persisting trees, just at a high level. So we're moving up in the abstraction, right? So that's where that most graphic, low-level graphic libraries are. If you had to do some kind of OpenGL programming or any kind of UI widget programming, you would be in retain mode. You would just populate a button onto the screen. And you would be able to interact with it. I mean, you don't have to manage it unless you want to change it, right? So everything is. And especially DOM is retain mode. So you just display some DOM on the screen. And then you can change the things that you want to change in response to callback. So retain mode goes a long way. But it has some problems. And these are the hard problems about UI. We are finally at a place where we can think about what the problems are. These are still unsolved. People are trying to solve them. No one has the perfect solution for it. So the biggest problem is reasoning about state transitions. When you have retain mode and you have, tell me if this sounds buggy to you, right? We have a giant mutable global state variable that gets updated by asynchronous callbacks randomly, right? Do you think anything could go wrong with that scheme, right? And that's the way we've been building GUIs most of the time. Like, till five or six years ago, everyone did things this way, right? And I'll tell you what changed like a couple of years ago. So that's the reasoning about state transitions. When did my state, my DOM element, change from one state to the other? It's very hard for you to reason about. So that's where bugs come in, right? And then you also want your UI definition to be composable. So you want to be able to define some components which are independent. And you can reason about those components independently and then compose them together in one big application. So when you have a giant DOM tree, right? How do you separate things, right? So that's a problem. Some architectures like MVC and I'll try to solve it. Like jQuery used to be pretty popular and basically with jQuery, you define a component that handles only a part of the tree, the DOM tree, right? And it's responsible for updating it and communicating with other components and things like that, but it was pretty ad hoc. For example, there wasn't a good story about how do you communicate with other components, right? So you don't know when you're getting something else from some other place, right? So it was very hard to reason about that. And mostly with functional programming, this being functional, the biggest problem we have is reasoning about things, right? So we want to have a system which, even if it's slightly more difficult to use, we want to be able to reason about it so that's much easier to refactor. And we know that there are no bugs with it. So then a couple of years ago, people started coming up with VDOM, right? Which is, I think React pioneered it, I'm not really sure if it did, but it came up around the same time where you basically are back to an immediate model, like retain mode wasn't working out for us. So we are building an immediate model on top of it where instead of changing things in a mutable shared state, you basically re-render the entire state every time, right? That's what VDOM is. You basically have, you think of your entire webpage as a giant DOM tree and you re-render it on every frame, right? So it's not exactly every frame, but you can think of it like that on every change, every event that happens. And React or virtual DOM is responsible for making it efficient, right? Because you need retain mode for efficiency. So VDOM allows us to go back to the immediate model. And I'm gonna argue that the most natural way of writing code is the immediate model, even though most UI libraries use retain mode, right? So Conquer uses something much more similar to an immediate mode of drawing stuff. Any questions so far? I'm gonna move on to, okay. So while writing Conquer, I basically took whatever I thought was great about existing UI libraries, right? So React has only two good things about it. And these are these two things. And they are functional views, which is basically the immediate mode that I just spoke about where you, a view is basically re-rendered conceptually at least on every frame or every event update. So that's called functional views because you get an event in and then you re-render your entire view without thinking about the state of the view that was there earlier, right? You just assume that there was, you don't have any shared state or safe state that you need to worry about. So it's a functional view. And React also has something new, which is component hierarchy, where you basically define a component, let's say foo, and then you can use it inside a larger component, right? So it has a nice way of doing that. So I wanna show you examples of both. So a functional view is basically just this, right? So you have a local state. This is specific to a component, which is the count of how many times a button has been clicked. And then you just render the button every time the count changes, right? So you're re-rendering the entire button. You don't care about what the earlier count was. Every time you render, you basically return this button thing with the new count as the contents, right? So this is a functional view. And then you can see that you were attached to an event handler that calls this mysterious function called setStake, which eventually calls render again. So it triggers render when you do a setStake. And then it gets a new count. And then you can have nested components where if you have a class called toolbar, it can basically reuse another component called toolbarItem. And it doesn't have to worry about plumbing things, right? You can just use it. One thing that it does need to care about is that how does communication happen between parent and child? So a toolbarItem may need to signal to the toolbar that it has been clicked so that toolbar can update its state for something. So the way React does it, and there are maybe other ways of doing it, but this is the most functional way of doing it, is that you pass a callback as a prop to the inner child, and then the child is responsible for calling the callback. So it's still callbacks, but it's slightly more principled, right? And when that callback is called, the parent component is free to do anything at once, right? And call setState again. So we've seen setState, we've seen callbacks. It's, these are all mysterious functions that are very imperative in nature because what you have is after you call setState, nothing else executes, and effectively some global loop takes over and calls your render function again. So your rendering is pure, but your setState and your callbacks are impure, right? So that's a big problem with React. And of course, even though we have minimized state, but we still have localState within a component. So state is not good wherever you use it. So to solve some of those problems, basically there's this language called Elm. How many people are familiar with Elm or heard of it? Okay, quite a few, but that's good. So the selling point of Elm of course is that it's a pure functional programming language, right? With types, strong types, algebraic data types, right? So that's the best part about Elm. But another thing that it improves on the React model, it still has a virtual DOM, but what it does is it refies the actual action that gets sent. So your view now does not call this mysterious setState function. It instead returns a data type that represents the action you're supposed to take, right? So in case of our previous example, where we had a button which shows a number, which gets incremented every time you run it, what the view can do is that it can return an increment data type. Is this syntax clear to everyone? I was hoping that it's not very complicated, even for people not familiar with Elm. So this is the view at the top where it shows a button. And again, we have an onclick event handler, but instead of calling setState, it specifically calls increment and passes down an address, which is like a pipe, right? So it's not calling a mysterious imperative function, it's doing something specific. And then you have an update function that is a pure way of managing your state. So the update function gets called automatically. So there's still some magic happening in the background, right? But the update function, what it does is it takes the action that was passed by the view, and then it changes your model in response, right? So you have two pieces of functional components there, and the plumbing between them is still a bit of a magic, but what this allows us to do is reason about the state transitions, right? Because every state transition will happen through the update function, and it will be through a specific concrete action data type. So you can inspect all of them, you can see what components and what action data type at what point of time. This allows us to do cool things like undo, redo, debugging, you know, those things. I'm not gonna go into that, but there are some videos and stuff on the web. But yeah, so this is the, this is why we use Elm, and again, these are the good things about Elm, so they are in Concur as well, right? So Concur is based on functional programming languages. It has strong types, algebraic data types, immutable data structures, and we use all of them. Some of the problems with Elm are apart from the one that I just said, which is that there are some magic bits to Elm, is that it's crippled. So it's a functional programming language, but it doesn't have some of the better parts of functional programming languages, like type classes. It doesn't have monads. I don't know if that's a positive or a negative. So you run into the lack of these pretty quickly. So it doesn't scale, right? It's the same scalability problem. If you're building a complex application, you have to do a lot of plumbing. There's a lot of boilerplate to work around the lack of these things. Like state monad is a great way to manage state, and Elm can't use it. So conquer allows state monad. Conquer does this, but better because it has monads. I don't wanna show you. Okay, finally, instead of virtual DOM, there's another way of solving this problem, and there are probably more ways that are out there that I don't know about, is FRP, which is Functional Reactive Programming, right? How many people have heard of Functional Reactive Programming? Oh, great. How many people have worked with some form of Functional Reactive Programming? Oh, still quite a few, okay. I'm happy about that, okay, great. So with FRP, basically, what you do is, you have Retain Mode, right? Which is a huge ball of mutable state, right? And you want to be able to reason about the transitions that that state takes place, right? So one way to do it is ignore the transitions, do what Elm and React do, which is just re-render the entire state every time. What FRP does is that it lets you create a graph with explicit dependencies between parts of the state, right? And it has concepts of time-wearing values, which are called events and behaviors, and it allows you to combine those time-wearing values in different ways, and then plug them into the graph, right? So for example, a simple example. Actually, I'm gonna show you an example later on, sir. But the concept is that you create a graph, and then you just let it run, okay? So you're kind of punting on how do you manage the state transitions, because you manage the graph, and that is your logic, and then you don't care about state transitions, right? So it's like a higher-level way of working with state transitions. One of the FRP libraries called Reflex that I've used in Haskell, it also uses monadic layout, which for some use cases is pretty great. So it allows you to render components, compose components together using monads. But it has some problems that I'm gonna show you. So yeah, so these are the FRP primitives. Basically, you have events which are things that take place in discrete points of time. So you have, for example, button clicks. So a button click will only happen at some specific points in time, and then you have behaviors which are things which always have a value at any point of time, right? So for example, system time. You can ask for the current system time at any point. So these are two primitives that you have, and then you can combine them using combinators. So this is just a sample of the combinators we have. You can convert an event to a behavior, right? So can anyone take a guess at how would you convert an event to a behavior? So if you have, for example, a button click, right? Which only happened at some point of time, and you wanted to get a continuous value out of that, right? So how would you do that? Right, but so the problem here is what should, at the time that the event fires, then you have a value. But what about the times that the event is not firing? So you need some kind of a default value to start with because the event has not currently fired, right? So hold is a way to convert from an event to a behavior. What it does is it takes a default value. That's the starting value. At the time you call hold, this is the default value that the behavior is gonna have. And then whenever that event fires, it basically updates the value that is returned by the behavior. So it's a very logical way of composing things, right? So you can convert an event to a behavior. You can convert a behavior to an event, and it's appropriately called sample. Basically you can think of it as sampling a behavior which has a value at all points. And you sample it at some specific intervals and you get the value there, right? So it requires an event also because that event, the second event, event B here, represents the points at which you want to sample, right? So it's a way of composing behaviors and events together. So you have a behavior which is think of it like a graph with a continuous line on it, right? So that represents a behavior. And then at specific intervals that this event fires that you've passed and then sample will just plug the values out of that behavior at those specific intervals. And it returns like this tuple of the value of the event just so we don't lose any information. It returns the value of the event also, which is B, and it returns the value of the behavior at that particular point of time, right? So, oh, I probably should have mentioned an event A is basically an event that has a value of type A, okay? So A could be, for example, an integer or a string or any type, right? Same with behavior. Behavior is a behavior of type A, right? So you can compose things like that and then you can combine multiple events together. So if you have two buttons and you have events that represent each of their clicks, you can join them together. So now you have an event that fires every time any of the buttons is clicked, right? So you can combine them together like that. Similarly, you can combine behaviors. And this is how you would use it. So if I wanted to have a button and some text, and the text gets updated from not click to click, every time you click the button, right? So this is how you would implement it. So this is do notation. How many people know about do notation? Less than I had hoped. So do notation is like imperative programming, right? But this is in functional programming languages. So what you have is basically, you have a do block, which is like begin and end, or you can think of as a function body. And then it does these things sequentially. So here it's creating a button and getting the event out of it called clicks. Now this event fires every time the button gets clicked. And then it's creating a text, but the value of the text is a behavior because think about when you wanna display something on the screen, you need something to be displayed at every point of time, right? It's not that it should appear only at certain intervals, right? So a text takes a behavior of string, right? So you pass it a behavior of string and it takes the responsibility of keeping the text label updated with the value of the behavior. So the way this thing works is that it shows a default value of not click. As I said, hold takes a default value. So the default value is not clicked, but then it converts, it takes an event called clicks and then it converts that to a behavior. So every time that event fires, it basically updates the value to whatever value was returned by that event. Now clicks does not return any useful value because a button clicked, yes. Clicks, yes, exactly. Yeah, yeah. Oh no, so these are lifted values. These are not primitive values. Yes, it does, but you need to lift it. So you can say lift unit, right? So it will lift it into an event. It's not really lift. I don't know exactly what that function is called, right? But there's a function to lift it. Oh, you mean if I replace clicks with something else? Yeah, oh, but what's important is the time at which it fires. So if you replace the clicks called here entirely, then you've basically broken the connection. So it will never know what time the click was done, right? So yes, exactly. Exactly, exactly. So you have a sequential set of statements. Each statement can potentially create a UI element and get some events or behaviors out of it. And these are basically time-wearing values, right? So, and then you can use this time-wearing values. You can compose different time-wearing values together and then pass it to a different widget that uses it to display its contents, right? And that's how you build a graph, basically, with FRP. Another thing here is that clicks does not have a useful value. So we basically map over all the values that clicks returns. So instead of returning unit, which is like a useless value, we return a string called click, right? So this is the syntax. It basically is an anonymous function here, which says that I don't care about what values return by clicks. I just want to, I always want to return the string clicked, right? So, yeah, that's a short introduction to how FRP works, right? Basically, you create this graph and this is like a high-level description of what should happen and then just let it run, right? The good things about FRP are that it gives us the concept of returning things from widgets, right? So a button returns a time-wearing value that represents whenever it's clicked. Text does not have a useful return value because it's just a label, it doesn't really do anything. But potentially it could also have a click handler if you're in a webpage or something. So it could also return an event. So that's one of the things that's in Conquer also. You can return values from widgets. And the other thing is that all of these widgets are functors so you can map over time-wearing values, right? So you basically are, you can change the value that is returned by an event or a behavior or a widget. So those are two things that are in Conquer as well. The problems with the FRP is that it's slightly more complicated, right? I'm sure lots of people here did not understand that sample of code. So it's difficult for new people to get started with. And it also turns out that it has, in my experience, an unpredictable complexity curve. So I've built large applications with the reflex. And I was just getting started with it. So it might be, some of it might be my inexperience, but what would happen is that if you want to refactor some things, then suddenly from a simple piece of code it will become very complex. So it's not a linear curve. It's very unpredictable. In some places it's linear. Some places it's exponential. And it's hard to know when that will happen. And then it uses monadic layout for, it uses monads for layout, which is, I think, an oversight. Layout is not monoidal. It's not monadic, it's monoidal. So basically layout is a way of composing multiple elements on the screen together. And monads should not figure into it. You should be able to take a widget, take another widget and put them on the screen together without thinking about monads, right? So it uses monads for widget composition, which I think is complicated and it has problems. And the place where it should provide a monad, it does not. So monads are good for sequencing things. So state transitions should be monadic, but it does not have a monad for that. It instead uses those time varying values that I spoke about. It does not have composable widgets. You can compose events and behaviors together, but not widgets, which is a problem. And if you have a lot of nested stuff, then sometimes it becomes too complicated, right? So which I already spoke about. So yeah, so let's come to Conquer. It's open source, so you can get it at GitHub, right? And it's also, this particular version is written in Haskell, but I also ported it to PureScript and there's also a JavaScript version. You can find all of them there, the links on this page. So in building Conquer, I only use the freshest ingredients that I could think of. Conquer is pretty new. It's only a couple of months old, right? So I would love feedback on this, but basically it's a strongly-typed functional language. So PureScript and Haskell both are great for this. It's a DSL for functional views. It really builds upon React's functional views, uses virtual DOM, and it takes that and builds upon that. It has components, but it does not have mutable state. It has no callbacks. Everything, communication between widgets happens not through callbacks, but through a monad, right? So it's a sequential way of getting things out of a widget and passing it to another widget. And I'm gonna show you examples of that. So no callbacks means that it's much easier to reason about, and it has three variants right now, and I'm always thinking of porting it to more languages. The JavaScript one, obviously it's not a pure functional programming language, but I think the JavaScript version also worked out great. It uses async generators. So yeah, so I mentioned earlier that we want to do things with as few tool tools as possible, and those tools should be orthogonal. So there are only two things that you need to know about in order to use Conquer. You don't need to know about monads to use Conquer, right, so there's just two things, which is when you compose widgets together, they are monoidal in the sense that you can append two things together, right? That's it, and then when you do a transition, so it's monadic, but what that effectively means that it's sequential, right? So you basically compose widgets to create a view, and then you transition to another view, which has again composed widgets in it, right? So that's the model you need to keep in mind, and this simple model goes a long way, right? From simple applications to very complex applications. So a widget basically is a very generic thing. It can have different types of views. Typically we'll use HTML for web views, but I envisioned Conquer can be used for desktop applications, or it can also do server-side rendering, so then you won't have HTML. You would rather generate a string that has the HTML content in it. So you can change the view depending on what backend you're using. Right now there are two backends, one is React-based and one is virtual DOM-based without React. Both of them use HTML as the view. And then a widget needs to have a return type. As I mentioned with FRP, you have things returning from a widget, but these are not time-wearing values, these are the values themselves. So a button in Conquer has unit as the return value, but it fires only once, effectively, right? So the button gets clicked and then it returns a unit. That's what really happens. And then it has a simple DSL for DOM elements. So text label would just be, it takes a string and then it displays a text label on the web page. As I already showed you in the Hello World example, this is the Hello World of Conquer. And then you can nest it together using arrays. You can see that lists are great for appending things together. So if you have two lists with some arbitrary widgets, you can append them together in a larger list. So that's why I use lists for DOM elements. So here you have a div with some properties. It has a class called header. And then I have a list of widgets that go inside that div. And to create this list of children, you can use list append, right? So you can get children from two different places and append them together. That's the point of monoidal layout. And you can wrap things together. So as I showed you, the div here wraps two text widgets. Each of these is separate independent widget. And then you can take the text widget and put it inside a button. And you can get this button. If you wanted to put two buttons, then again you can wrap them inside a div and you have two buttons just like that. So it's a very simple DSL for creating HTML. And you can have two buttons here like that. If you wanted to compose them vertically, then you can basically wrap them individually inside it. So what I wanna show here is that you can nest it as deep as you want. It's just simple HTML. And till that point, it's fairly similar to React. But it does event handling in a different manner. So it's not really set state and callbacks. The way it does it is that every widget, and again, this is similar to FRP. Do notation, you have things that happen in the sequence. You have a button and a text, right? But what the button does is that when it gets clicked, effectively the button disappears from the view in conquer. And then whatever happens, whatever widget is next in the sequence, that gets displayed. So this does a fundamentally different thing from the FRP example. Even though the structure is the same, you have a button and then a text, right? But with conquer, the sequencing is used for transitions between widgets. So you can show a button and then as soon as the button emits an event, you move to a text label display, right? This is pretty fundamental to conquer. So is there anyone who would like me to explain this more? I'll come to that, yeah. So yeah, but if you don't want the first thing to persist, you can just move on to another widget. Yes, yes, yes, exactly. Yes, yes, exactly. So I'm gonna answer both, right? So the same concepts apply to different kinds of events also with different data types. Return types. So yeah, it's in one of the following slides. Okay, so yeah, so okay, so what you have is this sequential widget composition and the way this widget composition works is that anytime an event fires, the entire widget disappears, the new widget comes in and that works in a nested format also. So if you have a div that has a button inside it, as soon as the button fires, the entire div disappears, right? So the entire UI that's nested around that event handler, the entire thing disappears, which seems kind of strange, right? But so if I have a button and I click on it, the button disappeared and it showed a text in a button. Now the button was inside a div, I click on it, the entire text and the button would disappear, then we came back. This also shows another feature where you have communities like forever, which basically don't let this entire thing end, it just keeps on running it again and again, right? So after the second widget ends, it just goes back to the first one again, it's like a loop, right? So you can, these are very easy to define, you can define them yourself. So that's the event model with Conker. The other thing that it does is that while you're transitioning from one view to the other view, that's a great place to have effects. So Conker has great effect support. You can do things like block stuff, you can use it for debugging, you can use it for bindings to another JavaScript library, for example, FRP is not that great for bindings because you don't have a clear sense of transition. You basically build a graph and then you let it run so you don't manage the transitions yourself. And with Conker, there are specific places where you have those transitions so you can put effects there. It doesn't affect anything in the view. So this is how you would define forever. It's basically just, given a widget, it runs the widget and then when it ends, it just calls itself again. It's like a tail call, right? So you don't need to understand the syntax completely but these combinators are very easy to define. So this was your question, right? So if you have multiple buttons with different data types, here is the same data type but I'm returning different values. And the way I'm returning different values is I'm, this dollar syntax is basically mapping over the event that gets returned, right? So this basically has two buttons with event handlers for each, right? When the button gets clicked and button event handlers generally return unit which is no useful value but I'm using the mapping to return hello from the first one namaste from the second one, right? So to answer your question, if you have two different data types you would map over them to make them the same data type. So if you have like int and string, you would probably put an either on top so you have left int, right string, right? To make it the same data type. So, and that has to be done only in this specific place and then you can take it out and then remove the wrapping. So the rest of the code doesn't have to deal with that wrapping and this shows that the widget itself is also can be mapped over and the event handler itself can be mapped over. So there's a subtle change here. Here I'm returning hello from the event handler and here I'm returning hello from the entire widget. It's the same thing. It does the same thing, right? So what it does is if you click on hello, it says hello sailor. If you click on namaste, it says namaste sailor, right? So that that's how you define it. So, I must skip over that. Okay, so this is a good example of what you said where you have an on change and you have an on focus, two separate event handlers, they return different things because on change has to return the changed value of the text on focus just says that it's focused to its unit and I wrap it in a data structure that abstracts over the differences, right? So change returns a string and focus doesn't return anything useful. This conquer model is generic enough to implement Elm architecture in it, which is very simple. So basically you define your state the way it is and you define your action data type just like in Elm and then when you compose the widgets together, you're basically doing it using conquer's model but the first part displays the entire view with the event handlers. This is like Elm's view function and as soon as any event handlers within this fires the entire view gets removed from the view, right? From the webpage. So, but then you have the value of that event handler with you, which is like the action from Elm's model and then you can use the action to update your state and call itself again. So here I'm, so I used the action whether it was whether you clicked on the remember me checkbox or you clicked on some text box or did whatever and then I call the same widget again with different set of parameters to represents that change in state. So this is effectively Elm's model and since it uses virtual DOM which is the same thing as Elm, so it boils down to the same thing in the application and this is what it comes down to. I can, every time I type something it fires an event but then it changes the value of the text box, right? But it doesn't end the entire application. So this was your question, right? So you want a persistent checkbox and text widget there. So how do you do that? So every time this event fires and it's about to be removed I just call the same widget again with the same parameters and it just gets displayed again and React makes it so or virtual DOM makes it so that you don't see the transition, right? So it just calls the same widget again with a different value of the text box and it displays that only when I click on submit does it actually end and update the text on top, right? So doesn't update it every time I type something here but it updates it every time I click on submit, right? So these applications are easy to build with a conquer and then because it's a monad you get like cool things like what if you wanted to show a list of forms and get all their values out in an array and this is sequentially so you should form one, get the value out, form two, get the value out and so on till the very end and then at the end you want a list of all the values that came out. So that's simply traverse. So you traverse over a widget and you get that behavior, right? So this scales, right? So this is the scalability thing, right? So you can use whatever monadic combinators you want to use and it'll just work, right? So persistent widgets, I also have another solution called signals which is like poor man's FRP, right? I'm just gonna take two minutes to quickly go over that. Basically a signal is an abstraction over a widget and again this is implemented in like half a page of code, right? So it's not very complicated on top of widgets but basically it's a widget that recursively calls itself. It's a forever looping widget and then signals provide a way to compose forever looping widgets together, right? So how much time do I have time? Okay, perfect, okay. Okay, so I'm almost done with most of my stuff but I'll leave some time for questions after that. So yeah, so with signals you can write a very similar code as what we had earlier but now it's a signal and all these divs and buttons, all those combinators that you've defined, I made them all generic. So they can be interpreted as signals or widgets, right? You just write them and depending on the type signature it does the right thing, right? It makes them a signal or it makes them a widget, right? So you don't have to change your code but now what has happened is that every time you click on a button it doesn't disappear from the view, right? Because it's a signal, it's a forever running widget. It, one good thing it has over FRP is that the return value from a signal is not a time varying value, it's a normal value, right? So you can, you don't have to deal with the complexity of joining events together, joining behaviors and events and doing those things. You can basically get a value out and then you can do pass it to another text label there and it just works regularly, right? You can just, you can have an effect that logs it as string and it will just work. Okay, so we have signals composed just like a regular monadic thing. So here I'm, I have that hello widget. I can run it twice and both of them will be on the screen at the same time because this is, this basically gives you what FRP gives you and it gives you that monadic layout which has its own problems. So signals have the same problems. So, but we also provide widgets to get over those and then signals can be easily converted to a widget by just calling dine. There's a function called dine and it becomes a widget now. It's all magic, right? So, and then what if you traverse over all signals instead of traversing over all widgets? So because signals are persistent, when you traverse over a form, let's say a hundred times, it'll show hundred forms in the same page and then you can fill all of them and then when you submit all of them it'll show you the result as an array, right? So signals have different semantics but it's the same code. The same code works for both signals and widgets. That's all I had. I wanted to show you some life code like this slide deck is written in conqueror. I can change code right now and it just immediately changes. But unfortunately we don't have a lot of time. So any questions that I can answer? Thank you. Thank you very much.