WEBVTT 00:00.000 --> 00:07.000 Hi, can everybody hear me? 00:07.000 --> 00:08.000 Yes. 00:08.000 --> 00:09.000 Okay, great. 00:09.000 --> 00:10.000 Hi, everybody. 00:10.000 --> 00:12.000 My name is Dave Thompson. 00:12.000 --> 00:14.000 I am the CTO at the Sprite Institute. 00:14.000 --> 00:18.000 And today, we're talking about functional reactive programming with propagators. 00:18.000 --> 00:20.000 Words you may or may not understand. 00:20.000 --> 00:21.000 Don't worry. 00:21.000 --> 00:22.000 I will explain them. 00:22.000 --> 00:26.000 But quickly, about Sprite Lee, Christine already explained, but working on the next generation 00:26.000 --> 00:27.000 of you centralized technology. 00:27.000 --> 00:31.000 So I probably won't belabor the point since Christine was just here. 00:31.000 --> 00:33.000 So let's get right into it. 00:33.000 --> 00:36.000 Before we get to the functional aspect, let's just talk about reactive programming. 00:36.000 --> 00:41.000 Who knows what knows what it is or has used a library for active programming. 00:41.000 --> 00:42.000 Okay. 00:42.000 --> 00:43.000 Little over half of the room I'd say. 00:43.000 --> 00:44.000 Okay. 00:44.000 --> 00:49.000 For those that don't know, the way I like to describe it is it's a way to work with time varying values 00:49.000 --> 00:52.000 without entering callback health. 00:52.000 --> 00:57.000 So without having to do like procedural event driven continuation passing style programming. 00:57.000 --> 01:01.000 So it's usually as a declarative abstraction. 01:01.000 --> 01:04.000 Sorry, abstraction on top of an event loop. 01:04.000 --> 01:10.000 So like in the web browser, you know, you have events for keyboard input, mouse input, etc. 01:10.000 --> 01:14.000 Rather than writing event callbacks, you have some declarative ways to do this. 01:14.000 --> 01:20.000 Graphical user interfaces are kind of where this type of programming seems to be used the most. 01:20.000 --> 01:23.000 And probably if I say the word react. 01:23.000 --> 01:26.000 Does everyone know what react is? 01:26.000 --> 01:27.000 Show of hands. 01:27.000 --> 01:28.000 Okay, basically. 01:28.000 --> 01:29.000 Okay, yeah. 01:29.000 --> 01:31.000 So react really means streamed. 01:31.000 --> 01:35.000 Reactive programming for like the web development community at large. 01:35.000 --> 01:36.000 So here's an example. 01:36.000 --> 01:39.000 Probably the simplest example from the react documentation. 01:39.000 --> 01:41.000 It's just a button. 01:41.000 --> 01:44.000 And then every time you click it, the click increments. 01:44.000 --> 01:47.000 So this is reactive, but it's not functional. 01:47.000 --> 01:50.000 So I want to talk about the functional side. 01:50.000 --> 01:55.000 At it's simplest, we just take reactive programming and then we use more peer functions. 01:55.000 --> 01:57.000 And we have function active programming. 01:57.000 --> 02:02.000 However, it's really hard to define FRP without probably making somebody mad. 02:02.000 --> 02:05.000 Because it's not a super well-defined term. 02:05.000 --> 02:07.000 And there's no way we can do that. 02:07.000 --> 02:10.000 It's really hard to define FRP without probably making somebody mad. 02:10.000 --> 02:13.000 Because it's not a super well-defined term. 02:13.000 --> 02:16.000 And there seems to be contention about what it really means. 02:16.000 --> 02:17.000 There's many forms. 02:17.000 --> 02:23.000 There's a continuous FRP, discrete FRP, push-based pull-based hybrid push-pull-based. 02:23.000 --> 02:38.000 But for this talk, I'm just going to say that discrete push-based FRP seems to be the most practical thing for dealing with things like just the event loops that we're typically used to. 02:38.000 --> 02:40.000 So I'm going to go with that. 02:40.000 --> 02:43.000 And this is not a new idea. 02:43.000 --> 02:47.000 This is a paper from ICFP in 1997 called Functional Reactive Animation. 02:47.000 --> 02:51.000 And I believe this is the origin of the term Functional Reactive programming. 02:51.000 --> 02:56.000 This was implemented in Haskell way back when. 02:56.000 --> 03:03.000 And I believe the authors of this paper would probably be mad about the definition of FRP that I just told you. 03:03.000 --> 03:06.000 So hopefully they're not ever going to see this. 03:07.000 --> 03:13.000 Unlike React, which is immensely popular, FRP has not had the same success of React likes. 03:13.000 --> 03:17.000 And I like to think of this blog post from the L language. 03:17.000 --> 03:22.000 If anyone's familiar with L, it was like a Haskell like that ran in the compiled JavaScript ran. 03:22.000 --> 03:23.000 But I was still around. 03:23.000 --> 03:27.000 But I had a big moment in the early-to-mid, you know, 2010s. 03:27.000 --> 03:29.000 And it went all in on FRP at the beginning. 03:29.000 --> 03:34.000 And then in 2016, they wrote this, the creator Evan wrote a farewell to FRP. 03:34.000 --> 03:42.000 And I kind of like to, to me, this is kind of like the death now of of FRP as like an idea that was gaining like. 03:42.000 --> 03:46.000 It was gathering steam and then it kind of, I feel like a kind of died here. 03:46.000 --> 03:53.000 But I, this FRP bug has been in my brain for longer than this and it's never really left. 03:53.000 --> 03:54.000 I keep being interested in it. 03:54.000 --> 03:59.000 And so never mind all that stuff, you know, maybe all these projects tried and failed. 03:59.000 --> 04:02.000 Let's, let's look at this with scheme. 04:02.000 --> 04:05.000 So here's a really wonderful, amazing demo. 04:05.000 --> 04:06.000 It was very complicated. 04:06.000 --> 04:09.000 And you see it's the same thing as in the React code that I showed you. 04:09.000 --> 04:11.000 Little button, I click in an increments. Oh, great. 04:11.000 --> 04:14.000 Well, that's amazing. Okay, talk over. 04:14.000 --> 04:19.000 What I'm going to show is, I'll show you some scheme code. 04:19.000 --> 04:24.000 So don't worry too much about understanding this, but I want to show that it's declarative and functional. 04:24.000 --> 04:28.000 In the sense that we, you're not going to see a set bang here or any kind of mutation. 04:28.000 --> 04:32.000 We, we have this, I'm calling themselves a, they hold time-bearing values. 04:32.000 --> 04:36.000 This one's going to hold click notifications. 04:36.000 --> 04:41.000 Concepts that we're used to in functional programming are like doing operations on list, map pretty well. 04:41.000 --> 04:45.000 So we're going to fold and it's a fold not over a list, but over time. 04:45.000 --> 04:47.000 We're going to take in the click cell. 04:47.000 --> 04:51.000 We're going to have an initial value of zero because the initially the user hasn't clicked the button at all. 04:51.000 --> 04:55.000 And every time an event comes in, we're going to modify that kind of, we're going to increment it. 04:55.000 --> 04:59.000 And then good thing Christine was just talking about SXML. 04:59.000 --> 05:01.000 This is the next SXML template. 05:01.000 --> 05:05.000 And what we do is we have an on-click handler here. 05:05.000 --> 05:07.000 And we got this on-quote thing. 05:07.000 --> 05:09.000 We turn this click cell. 05:09.000 --> 05:10.000 We make a listener for it. 05:10.000 --> 05:16.000 So every time a click event comes in, we update our little FRP cell. 05:16.000 --> 05:18.000 And then we splat in the count. 05:18.000 --> 05:22.000 And so this refers to the value of the cell. 05:22.000 --> 05:26.000 The engine behind all of this just ensures that the UI is updated. 05:26.000 --> 05:33.000 And so this presentation that I've been showing you is running the web browser is running a scheme program. 05:33.000 --> 05:35.000 This is the source code for the slide you just saw. 05:35.000 --> 05:41.000 So this is a web assembly program that is a scheme program called the web assembly running these slides. 05:41.000 --> 05:44.000 So this is the actual code of the demo I just showed you. 05:44.000 --> 05:48.000 So we'll go back to the presentation. 05:48.000 --> 05:50.000 I think I have to click off of here. 05:50.000 --> 05:52.000 Okay. 05:52.000 --> 05:56.000 So I can't talk about FRP without talking about glitches. 05:56.000 --> 05:59.000 I can't really talk about reactive programming general without talking about glitches. 05:59.000 --> 06:05.000 The most important job of any reactive library or framework is to avoid glitches. 06:05.000 --> 06:16.000 And a glitch is usually a brief small, like tiny moment of time, where a time varying value gets computed with a mix of scale and fresh data. 06:16.000 --> 06:20.000 And it becomes often becomes user visible and it's like a flash of something weird. 06:20.000 --> 06:24.000 And it comes in it goes, but it leads to like a janky user experience. 06:24.000 --> 06:26.000 And we don't want this. 06:26.000 --> 06:29.000 So I'm going to try to walk through this little thing. 06:29.000 --> 06:32.000 I can explain glitches with just a graph of four nodes. 06:32.000 --> 06:37.000 So right here, it's just a very simple data flow graph. 06:37.000 --> 06:39.000 A is the root. 06:39.000 --> 06:40.000 Numbers enter here. 06:40.000 --> 06:42.000 I'm just going to be working with integers. 06:42.000 --> 06:44.000 And so it gets any time A changes. 06:44.000 --> 06:45.000 We take A times two. 06:45.000 --> 06:46.000 We put it in B. 06:46.000 --> 06:47.000 Take A plus one. 06:47.000 --> 06:48.000 Put it in C. 06:48.000 --> 06:51.000 And then D depends on both B and C and we just take the difference. 06:51.000 --> 06:54.000 And so at the start, the cells contain nothing. 06:54.000 --> 06:57.000 We have to bootstrap our graph. 06:57.000 --> 07:01.000 So somehow we insert the number two and that kicks off reactivity. 07:01.000 --> 07:04.000 So it flows to B. 07:04.000 --> 07:05.000 And we double it. 07:05.000 --> 07:06.000 So we get four. 07:06.000 --> 07:07.000 We add one. 07:07.000 --> 07:08.000 We get three. 07:08.000 --> 07:10.000 And then finally we take the difference and we get one. 07:10.000 --> 07:11.000 Great. 07:11.000 --> 07:12.000 All looks well. 07:12.000 --> 07:16.000 However, let's take another another approach to it. 07:16.000 --> 07:18.000 Another data flow path. 07:18.000 --> 07:20.000 So we come in at the root again bootstrap. 07:20.000 --> 07:22.000 We update this value to three. 07:22.000 --> 07:26.000 We propagate to to node B. 07:26.000 --> 07:27.000 We double it. 07:27.000 --> 07:28.000 We get six. 07:28.000 --> 07:32.000 But instead of going to node C, we go to node D. 07:32.000 --> 07:35.000 Node D depends on B and C. 07:35.000 --> 07:37.000 So we take the difference and we get three. 07:37.000 --> 07:38.000 But that's wrong. 07:38.000 --> 07:41.000 Because the value here is three. 07:41.000 --> 07:44.000 So what we really want is the value two. 07:44.000 --> 07:49.000 But because this cell refreshed before this one, we have a glitch. 07:49.000 --> 07:54.000 And so eventually, after two more steps, converges to the correct value. 07:54.000 --> 08:00.000 But we have a moment that's probably going to annoy a user somewhere in the interface where the value is wrong. 08:00.000 --> 08:02.000 So this is no good. 08:02.000 --> 08:04.000 How do we avoid glitches? 08:05.000 --> 08:09.000 Reactive libraries typically do something like a topological sort. 08:09.000 --> 08:13.000 So D is below nodes B and C in the graph. 08:13.000 --> 08:16.000 So B and C should be refreshed first and then D. 08:16.000 --> 08:20.000 And then we ensure that D is always computed with fresh values. 08:20.000 --> 08:22.000 But we have a restriction. 08:22.000 --> 08:24.000 Once we add that property. 08:24.000 --> 08:27.000 The node graph must be a cyclic. 08:27.000 --> 08:30.000 And only, and therefore as a consequence, 08:30.000 --> 08:39.000 only a subset of possible interfaces that we can implement with event callbacks are now expressable with reactive programming or functional reactive programming. 08:39.000 --> 08:43.000 So it turns out. 08:43.000 --> 08:45.000 We will be able to remove this restriction. 08:45.000 --> 08:47.000 But I want to show an example. 08:47.000 --> 08:50.000 So this is a color picker diagram. 08:50.000 --> 08:54.000 Here we have the RGB values for representing color that way. 08:54.000 --> 08:58.000 And then on the other side we have a hue saturation value. 08:58.000 --> 08:59.000 Sliders. 08:59.000 --> 09:03.000 And what we would like to have happen is any time you manipulate one of these sliders. 09:03.000 --> 09:05.000 The sliders over here change. 09:05.000 --> 09:09.000 So we convert RGB to HSV and update the sliders accordingly. 09:09.000 --> 09:12.000 And when you change any of the HSV values. 09:12.000 --> 09:16.000 We convert HSV to RGB and update these. 09:16.000 --> 09:18.000 So there's circularity there. 09:18.000 --> 09:20.000 Like you see in the middle. 09:20.000 --> 09:25.000 And so we can't express that with acyclic reactivity. 09:25.000 --> 09:28.000 But acyclic reactivity is the norm. 09:28.000 --> 09:30.000 And it's what is popular. 09:30.000 --> 09:36.000 And it seems like what's going to continue to be used in the industry at large. 09:36.000 --> 09:39.000 This is a screenshot of a TC39 proposal. 09:39.000 --> 09:42.000 The standards group responsible for changes to JavaScript. 09:42.000 --> 09:44.000 They're working on something called signals. 09:44.000 --> 09:47.000 And it's a proposal for one way data flow in JavaScript. 09:47.000 --> 09:54.000 And it's going to be a reactive libraries in JavaScript to bring an API to JavaScript itself. 09:54.000 --> 09:57.000 But so that's the state of the art there. 09:57.000 --> 10:01.000 But I wouldn't be up here if I thought cyclic reactivity was impossible. 10:01.000 --> 10:02.000 It's very possible. 10:02.000 --> 10:05.000 And the secret ingredient is propagators. 10:05.000 --> 10:07.000 Has anyone heard of propagators? 10:07.000 --> 10:08.000 Okay. 10:08.000 --> 10:12.000 Much smaller group of people than new about reactivity in general. 10:12.000 --> 10:19.000 So I want to introduce you to one of my favorite PhD dissertations, which I feel is a weird thing to say. 10:19.000 --> 10:22.000 Because who has a list of their favorite ones. 10:22.000 --> 10:25.000 Normally they're so dense they're hard to read. 10:25.000 --> 10:27.000 I got to trust me on this. 10:27.000 --> 10:28.000 This one isn't. 10:28.000 --> 10:31.000 This is by Alexei Raduel, who was a PhD student MIT. 10:31.000 --> 10:33.000 This is from 2009. 10:33.000 --> 10:37.000 Propagation networks, a flexible and expressive substrate for computation. 10:37.000 --> 10:38.000 It is a fantastic read. 10:38.000 --> 10:43.000 I'm going to cover just a little tiny bit of that paper that talks about FRP. 10:43.000 --> 10:47.000 And no more, but I really recommend if any of this peaks your interest. 10:47.000 --> 10:48.000 Go there. 10:48.000 --> 10:52.000 Everything I'm about to tell you is derived from it. 10:52.000 --> 10:54.000 So what the hell are propagators? 10:54.000 --> 10:55.000 This is a lot of text. 10:55.000 --> 10:56.000 I'll just read the bold part. 10:56.000 --> 11:02.000 There are autonomous independent machines interconnected by shared cells through which they communicate. 11:02.000 --> 11:09.000 And this is straight out of Gerald Susman's and I'm forgetting the co-author right now. 11:09.000 --> 11:12.000 But software design for flexibility from 2021. 11:12.000 --> 11:19.000 If you liked SICP and you want something similar to it that's not from the 80s with additional more advanced topics, 11:19.000 --> 11:22.000 check that book out MIT press. 11:22.000 --> 11:23.000 Okay. 11:23.000 --> 11:26.000 So in real simple terms, cells are nodes. 11:26.000 --> 11:30.000 But notably they contain partial information. 11:30.000 --> 11:35.000 This is Alexa Redwell's key insight in his dissertation. 11:35.000 --> 11:38.000 You can including partial information being nothing. 11:38.000 --> 11:44.000 So there's initially a cell contains nothing and over time it accumulates information. 11:44.000 --> 11:47.000 And this can get particularly complicated. 11:47.000 --> 11:55.000 A lot of propagator, lore and research goes into AI systems and like truth, maintenance systems and stuff. 11:55.000 --> 11:58.000 I'm going to talk about something much simpler. 11:58.000 --> 12:00.000 You can get pretty crazy. 12:00.000 --> 12:02.000 And the propagators you can just think of as the edges. 12:02.000 --> 12:06.000 They're the things that take values from some input cells. 12:06.000 --> 12:09.000 Just some computation and then write them to one or more output cells. 12:09.000 --> 12:13.000 But notably this relationship between cells can be one to one. 12:13.000 --> 12:14.000 It can be one to what many. 12:14.000 --> 12:15.000 It can be many to many. 12:15.000 --> 12:20.000 There's no restriction on that. 12:20.000 --> 12:27.000 And also there's no restriction on when propagators like fire and when they refresh themselves. 12:27.000 --> 12:34.000 So propagator flow is dumb and it's dumb on purpose to meant to be very easy to implement. 12:34.000 --> 12:41.000 And so propagator networks by definition, they have no order of evaluation and they have no directionality restrictions. 12:41.000 --> 12:47.000 So if we want to build reactivity on propagators, we can't do topological sort. 12:47.000 --> 12:49.000 So we have to do something else. 12:49.000 --> 12:50.000 So we have a problem. 12:50.000 --> 12:55.000 If we don't solve the problem, we're going to have glitches and we're going to have a terrible reactive system. 12:56.000 --> 13:05.000 So as is often the case, there's a lot of things in computer science where you start with some kind of unordered system and you put order on top of it. 13:05.000 --> 13:07.000 Well, propagators are no different. 13:07.000 --> 13:14.000 I'll actually write a dual-explained that using an approach that really resembles logical timestamps in a distributed system. 13:14.000 --> 13:19.000 If you're familiar with logical clocks, transport timestamps, vector clocks, very similar concept. 13:19.000 --> 13:32.000 What we want to do is when we bootstrap our nodes, when data comes into it from the outside world somewhere, we want to make sure that each piece of data is tagged with some kind of unique identifier for each piece of data. 13:32.000 --> 13:39.000 And then some kind of logical timestamp, that's increasing monotonically with each change. 13:39.000 --> 13:46.000 And so as values accumulate and flow through the graph, you'll get many such pairs and these pairs form a vector clock. 13:46.000 --> 13:54.000 And with that, you can tell if the data that you're about to use is fresh or not. 13:54.000 --> 14:04.000 And so we can halt propagation when when a propagator fires and it discovers that its inputs have differing timestamps for the same identifier. 14:04.000 --> 14:08.000 One says that the time was one when this value came in and the other was two. 14:08.000 --> 14:20.000 That's conflicting. We have old and new mixed together. We should stop right there. We need to wait in order to actually do the transformation that we want to do so we halt. 14:20.000 --> 14:25.000 And that enables circularity without infinite loops. 14:25.000 --> 14:36.000 And so the trade-off here is that there is a bit of redundant computation because a propagator may fire when it can't actually do anything yet and it has to stop and it has to know that. 14:36.000 --> 14:42.000 So versus topological sort, you kind of visit each node and you know it's ready to go. 14:42.000 --> 14:47.000 But the total amount of redundant computation is actually quite minimal. 14:47.000 --> 14:57.000 And so without any ordering guarantees, a much simpler substrate, much simpler infrastructure, we can still get the same properties that we want values that converge without glitches. 14:58.000 --> 15:07.000 And so my definition of FRP on propagators is that it's the propagation of a femoral values. A femoral values are things that change over time. 15:07.000 --> 15:15.000 And so in my prototype implementation there is a type of record type and scheme is just called a femoral. 15:15.000 --> 15:18.000 It's a box that has any arbitrary value. 15:18.000 --> 15:26.000 And then on the side it has a set of sources. It's the vector clock. It has all the information from once that value came, you know. 15:26.000 --> 15:33.000 It's derived from these identifiers at these particular points in logical time. 15:33.000 --> 15:36.000 And that is enough to get what we need. 15:36.000 --> 15:45.000 I want to make a quick note. I mentioned this earlier, but it's not just I showed a fold earlier, but pretty much any list processing idiom translates really well to FRP. 15:46.000 --> 15:50.000 You're just not mapping over a set of pairs. You're mapping over time. 15:50.000 --> 15:55.000 So map, fold, filter. You get the idea. All these things, you know, map pretty naturally. 15:55.000 --> 16:02.000 So as a functional programmer or a scheme programmer or a list programmer that's used to these things, I think you can get with it pretty quick. 16:02.000 --> 16:07.000 So let's go back to the color picker. You know, I showed this graph earlier. 16:07.000 --> 16:10.000 And I wouldn't show it if we couldn't do it. 16:10.000 --> 16:22.000 And here it is. So this is running in the slide. This is actually code that's using propagators running in the hoot scheme interpreter, which has been compiled to web assembly and running in the browser here. 16:22.000 --> 16:32.000 So you see as as I adjust the sliders in the RGB, the HSV side changes and we have the little color swatch up there to tell you what it is and the hex code if you want to copy it out in some other application. 16:32.000 --> 16:37.000 And here I am changing Q saturation and value and the RGB sliders go. 16:37.000 --> 16:47.000 So yeah, it works and don't just take my word for it. 16:47.000 --> 16:53.000 I mean, I guess you have to also take my word that this is real code that runs and I didn't just do smoke and mirrors on you. 16:53.000 --> 17:02.000 But this is kind of, I'm going to have a hard time with the resolution of this fitting it in a single page. 17:02.000 --> 17:15.000 But just to show you, I've been working on some syntax that's not very good right now to define recursive graphs of notes. 17:15.000 --> 17:29.000 And so here are the values that become our sliders. We have the RGB group and as RGB and then HSV group HSV one thing I haven't talked about is what the heck is this group. 17:30.000 --> 17:39.000 Turns out that so RGB those are three facets of the same object like they they compose together to form an RGB expression of color. 17:39.000 --> 17:48.000 And so what we want is that all three of these, they have the same identifier and they share the same timestamp counter. 17:48.000 --> 17:56.000 So when you change any one of those you're changing this identifier that becomes the RGB group. 17:56.000 --> 18:02.000 You know it starts at zero and change R goes to one you change B it goes to two they're linked together. 18:02.000 --> 18:14.000 And that proves to be an essential part of making the propagation work so essentially facets of of a composite object that are at the root of your reactive graph. 18:14.000 --> 18:23.000 You you generally you want to make sure that they are using the same logical time and they're kind of understood as like one machine in the system. 18:23.000 --> 18:33.000 If that didn't make sense don't don't worry too much about it and then finally my kind of work in progress terrible notation for. 18:33.000 --> 18:47.000 The edges in the graph if you've ever used the dot notation and graph is it's like a kind of a list be version of that, but I'm just saying that Rg and B those cells combine. 18:47.000 --> 18:54.000 To write a value to the RGB cell and RGB color is a constructor for an RGB color record. 18:54.000 --> 19:16.000 But it's bi-directional so when RGB changes we destructure the record and we put the RGB values in their corresponding cells the same thing applies to HSV just with the HSV record and it's it's accessors and then the the good stuff happens here it's just a this is a bi-directional expression of when HSV changes. 19:16.000 --> 19:24.000 We convert it to RGB and we write it to the RGB cell when RGB changes we convert it to HSV and put it in the HSV cell. 19:24.000 --> 19:32.000 So that's like the that's the that's the entire propagator network really and then all that's left to do is hook it up to a UI. 19:32.000 --> 19:38.000 And let's see if I can get it all I can get it mostly on one screen. 19:38.000 --> 19:43.000 The top it doesn't really matter we we have some procedures to convert an RGB color to a hex train. 19:43.000 --> 19:49.000 I'm just like jet splatting out some gross CSS there for the color swatch and then again we have. 19:49.000 --> 19:55.000 This is the slide that I just showed you this is the record type for these slides in the the slideshow system. 19:55.000 --> 20:01.000 And another quasi quote and so another SXML template and then I have some helpers to do the sliders for me but notably. 20:01.000 --> 20:12.000 There's Rgb I'm referring to these cells and the rendering engine will hook things up such that there it does all the callback stuff under the hood. 20:12.000 --> 20:21.000 So there's a slider and the sliders have a value anytime the cell changes it'll it'll call it'll update the value of the dom node for that slider. 20:21.000 --> 20:28.000 And anytime someone slides it that value will then get placed into the cell as an updated value and then the propagation starts. 20:28.000 --> 20:34.000 So this is how values enter the propagation graph and the graph is bootstrapped. 20:34.000 --> 20:44.000 But it's a two way binding so so if you're used to two way binding for many other web UI framework it's it's the same thing but just expressed in a in a different way. 20:44.000 --> 20:51.000 So yeah, that's the basics of the of the code and I am close to done here. 20:51.000 --> 20:54.000 I just wanted to show you that just so future work. 20:54.000 --> 21:07.000 I cobbled this together pretty fast before for them I had done I wrote a blog post about this in 2024 and then I kind of just stopped doing anything with it and I kind of refreshed it for this talk. 21:07.000 --> 21:19.000 And so I did a lot of re-implementation of things and it's kind of a mess but it works but it's not optimal there's a lot of places that are slow so to make this actually usable from scheme. 21:19.000 --> 21:28.000 In real programs that are not just demos I'd like to optimize internal algorithms to make the propagation better and generate less garbage. 21:28.000 --> 21:37.000 So we run the garbage collector less frequently which could lead to UI junk you know the be a bad experience with the GC's running all the time. 21:37.000 --> 21:44.000 And I'd like to publish a library that works for both the guy virtual machine and also on the web for who I mean I mostly want to use this for web UI's. 21:44.000 --> 21:53.000 And then I'd like to actually test drive it in some of the demos that we do it sprightly we've been wanting some kind of UI framework for a while and since we we use scheme. 21:53.000 --> 22:01.000 As Christine was saying it's a great thing for doing all of our experimentation but on the other hand the flip side is that you end up rolling your own stuff a lot of the time. 22:01.000 --> 22:08.000 So you know I don't I don't want to use reactive you or anything like that I want I want to use our scheme thing so I want to try it out there. 22:08.000 --> 22:16.000 So that's really it you know I do all this with sprightly if you like what we do at all where if I want to see three my profit. 22:16.000 --> 22:24.000 You know we can't do the work we do without help from from you all so please spread the Institute slash donate. 22:24.000 --> 22:31.000 If you become a recurring donor we will shout you out on our on like every blog post we do I plug. 22:31.000 --> 22:37.000 I check out our donations list and I thank everybody that's that's got monthly donations set up in there on our various tiers. 22:37.000 --> 22:45.000 So anyway we greatly appreciate your support support I'm done thank you do we have time for questions. 22:45.000 --> 22:52.000 Like clapping for myself over here I don't understand. 22:52.000 --> 22:57.000 Okay let's see I'll start here. 22:57.000 --> 23:09.000 The question was in my demo I have this arrow operator and what is that. 23:09.000 --> 23:16.000 It's it's a syntax literal it's just used to separate the inputs from the outputs because the. 23:16.000 --> 23:23.000 I just needed some notation to show that it's like values are flowing from the left to the right. 23:23.000 --> 23:26.000 It's it's not no so I just wrote. 23:26.000 --> 23:34.000 This is what needs development like we need I need an ergonomic like domain specific language for doing this and in the very little time I had. 23:34.000 --> 23:40.000 I thought of just using what graph is does and you just do a little arrow. 23:40.000 --> 23:48.000 Yeah yeah yep so it's I could show you the macro after it's kind of it's it's trash to be honest with you but. 23:48.000 --> 23:53.000 Yeah I think it's like approximately something that you would want but like without the arrow. 23:53.000 --> 24:00.000 It looks like this and it's like if you're reading that it's like how do I know that I don't know what that's doing like if I read it like. 24:00.000 --> 24:07.000 But with the arrow looks like okay values are flowing from the left to the right so that's just kind of the intent that I wanted to put behind this syntax. 24:07.000 --> 24:09.000 But it's just a literal there. 24:10.000 --> 24:11.000 Thank you. 24:11.000 --> 24:12.000 Okay. 24:12.000 --> 24:16.000 Still like in this piece of code. 24:16.000 --> 24:22.000 Yeah like in this case the propagator doesn't execute like each individual function like. 24:22.000 --> 24:28.000 It goes a little signed a value one at a time or sort of happens like. 24:28.000 --> 24:32.000 The group gets a reassign all in what's because it's a group right. 24:32.000 --> 24:39.000 Yeah so for the groups what happens is when a cell is updated like said the R cell gets updated. 24:39.000 --> 24:46.000 As part of it it looks at all the members of its group and it calls the special thing to fresh in the timestamp on it. 24:46.000 --> 24:55.000 So it doesn't propagate that value from those other cells but it does ensure that it knows about the timestamp going up. 24:55.000 --> 24:58.000 So they just have to all have the same notion of logical time. 24:58.000 --> 25:09.000 And if and if they do then the propagation works if if that didn't happen the problem becomes that there's a lot of redundant computation that happens if they if they're not like synced up in that way. 25:09.000 --> 25:13.000 I don't think I can explain that in a succinct way right now. 25:13.000 --> 25:14.000 Yeah. 25:14.000 --> 25:15.000 Okay yeah welcome. 25:15.000 --> 25:17.000 Let's see oh all the way in the back. 25:17.000 --> 25:18.000 Yeah. 25:18.000 --> 25:19.000 I think that is up at the end. 25:19.000 --> 25:21.000 Look at the air sometimes here. 25:21.000 --> 25:23.000 I was here is. 25:23.000 --> 25:31.000 So I specifically like the form of classic pepperoni from like the little alien. 25:31.000 --> 25:35.000 There's continuous time and simple formal semantics. 25:35.000 --> 25:37.000 And the distinction of the people here is an event. 25:37.000 --> 25:42.000 Yeah where does your implementation relate to this. 25:43.000 --> 25:49.000 Do you have a similar model of like the semantics which operators supposed to do here. 25:49.000 --> 25:54.000 I think the distinction or is our things grouped together more. 25:54.000 --> 25:58.000 Let's see okay the question was about if. 25:58.000 --> 26:00.000 If I'm used if or. 26:00.000 --> 26:09.000 Hmm how do we even say the question about continuous FRP semantics versus discrete semantics I think was the core of the question. 26:09.000 --> 26:10.000 Sorry. 26:10.000 --> 26:13.000 Did I get that roughly right I. 26:13.000 --> 26:15.000 Yeah it does not exist. 26:15.000 --> 26:19.000 So I'll just I think the short answer is it's not classic FRP. 26:19.000 --> 26:21.000 I have not gone the continuous route. 26:21.000 --> 26:27.000 I've gone for discrete event based things because we're used to discrete event based systems. 26:27.000 --> 26:30.000 And it seems like the fastest way to get something that works. 26:30.000 --> 26:35.000 But I'm also I've never used a continuous FRP system. 26:35.000 --> 26:38.000 So it could be that I'm just ignorant. 26:38.000 --> 26:42.000 And I need some exposure to that to know what I could take from it. 26:42.000 --> 26:45.000 So do you have any recommendations I would love to hear. 26:45.000 --> 26:48.000 Yeah thank you for your question. 26:48.000 --> 26:49.000 Yeah. 26:49.000 --> 26:52.000 I'm explaining which is you mentioned that. 26:52.000 --> 26:56.000 When resolving two values for different time exams you have to stop the date. 26:56.000 --> 26:57.000 Yes. 26:58.000 --> 27:14.000 So the question was why not just use the freshest value if there's a mix of the two. 27:14.000 --> 27:22.000 And in the general case there could be many things that are not fresh about it. 27:22.000 --> 27:25.000 There could be more than one. 27:25.000 --> 27:31.000 And it's not you're not guaranteed you could have two stale values actually for the same thing. 27:31.000 --> 27:36.000 And that would also result in a glitch because it may be maybe some third that maybe some third input 27:36.000 --> 27:38.000 Propagated over there. 27:38.000 --> 27:44.000 So like you know add a fifth node to the graph and that one updated and you still have stale data. 27:44.000 --> 27:48.000 So I think in the general case it's tough maybe there's an optimization. 27:48.000 --> 27:51.000 So I've just went the dumb way that I know works. 27:51.000 --> 27:52.000 Yeah. 27:53.000 --> 27:55.000 I think that's is that it for questions. 27:55.000 --> 27:57.000 We could take it outside or. 27:57.000 --> 27:59.000 Well okay I will be we can hallway track it. 27:59.000 --> 28:01.000 Happy to answer questions outside.