In this session, you learn about a functional way to do event handling called functional reactive programming. So what is functional reactive programming or FRP to which it is often abbreviated? Well, if you just talk about reactive programming, it's about reacting to sequences of events that happen in time. And the functional view of this is in a nutshell, to aggregate an event sequence into a signal. So a signal is a value that changes over time, but we're no longer looking at the individual events as they fire. We're looking at the signal as a whole. So an abstract view of a signal is to say it's a function from time to the value domain. And once we have that we can replace propagating updates to mutable state by defining new signals in terms of existing ones. So instead of having the individual events and their updates, we see the signals as a whole. So let's make this concrete with an example, let's say you have a mouse that moves around the surface. The event-based imperative you would be that whenever the mouse moves you get an event that says mouse moved and the new position where it is now. By contrast, the FRP view of that would be to say, well, we represent this curve as a signal from time to the current mouse position. So it's a function from time to points in a two-dimensional space that you see here. So how was this change in viewpoint invented? Well, FRP really started in 1997 with the paper Functional Reactive Animation by Conal Elliot and Paul Hudak and they also published a library to go with it, which was called Fran that was very influential. There have been many FRP systems since both standalone languages and embedded libraries. Some popular examples today are Flapjax, Elm, React.js or also React Native. So a lot of the event propagation on JavaScript frameworks is now done in a functional reactive way using React.js for instance. There's another branch of reactive programming, which is essentially data flow programming systems based on events streaming. An example is Rx those are related but the term FRP is not commonly used for them. We use FRP by means of a minimal class, which we define ourselves and whose implementation is explained at the end of this module. This implementation is modeled after a system called scaly react, which is described in the paper Deprecating the Observer Pattern. So what can we do with a signal? The two fundamental operations, the first operation is to obtain the value of the signal at the current time. So if the signals are functions then obtaining the value of a signal at the current time is function application. In our library this is consequently expressed by just writing function application like this. So the current time is implicit. So MousePosition() would say the mouse position at the current time. And the second fundamental operation is to define a signal in terms of other signals. In our library this is expressed with the signal constructor. So for instance, we could define a signal in rectangle, it says is a position in the rectangle given by the lower left and upper right corners. That's a signal that gets the mouse position, the mouse position at this point in time. And it then asked whether the position is between LL and UR. So that can be visualized like this. So now you have from this original signal, you have the bounding box between LL and UR. And your new signal would be a function in time that goes essentially like this first it's not in the bounding box is false, then it's true. And then after some time it's again false. So this would be true. This would be false. So you see we can transform one signal into another using the signal constructor. So it's worthwhile taking a step back and see what we've done here. Here's the in rectangle function that we would define normally without functional reactive programming. So it's just the body of the signal here and it returns a Boolean. Now, that means that every time we call inRectangle will tell us whether the current mouse position is between LL and UR. Contrast that with a new definition of it's in rectangle that returns a signal of Boolean. That inRectangle creates a signal that at any point of time is equal to the test where the most position at that point in time is in the box LL or UR. So it means if you write let's say VoR B = inRectangle, some corners, L and R. Then that will give us a Boolean result B that reflects whether at the time when we evaluated this call, the current mouse position was between L and R. And the result will stay the same forever afterwards. Whereas, for the signal version if we set it up like this VoR signal equals inRectangle (L, R). So that would give us a signal which we can query it arbitrary times in the future. And each time we query the signal, it might give us a different result depending on the mouse position at the time when we query the signal. The signals in text can also be used to define a signal that has always the same value. So that's a constant signal. For instance, val sig = Signal(3) is a signal that is always 3. So the idea of functional reactive programming to see signals as essentially time varying functions is quite general. It doesn't prescribe whether signals are continuous or discrete, and also it doesn't prescribe and how power signal is evaluated. We could think of several possibilities to evaluate a signal. One way would be to evaluate it on demand to store the signal as essentially a formula and every time it's value is needed to be evaluated. Another idea is to sample a signal that's continuous at fixed or varying time interval at certain points and to interpret in between. Or if the signal is discreet, we could also update it internally and propagate the updated value automatically to dependent signals. That last possibility is in a sense the functional analog to the observer pattern and that's what we will pursue in the rest of this session. How do we define a signal that varies in time? The possibility we've seen so far was to take an externally defined signals such as mouse position and then map over them. That means defined derived signals in terms of mouse position. So since mouse positions varies over time, so do the derived signals. Or we can do that internally using a Signal.var. So expressions of type signal cannot be updated, but our library also defines a subclass var inside signal. So Signal.var for signals that can be changed. Signal.var provides an update operation which allows to redefine the value of a signal from the current time on. So for instance, we could set up a signal like this. It's a Signal.var(3). So it is at this point in the computation always 3. But at some later point we could say sig.update(5). And that means from that point on the signal would return 5 instead of 3. In fact, we can make this somewhat nicer by using Scala special update syntax. In Scala calls, to update can be written as assignments. You might have seen this already when you worked with arrays, for instance, for an array arr we can write arr(I) = 0. In case you wondered what that is, it's actually translated to arr.update( i, 0). So it's really a call of an update method on an array. This update method can be thought of as you see here. So it's in class array. The update method takes an index and a value and it would then set the element of the array at that index to the new value. So there's a general rule in Scala that enables it. The rule is that if you have an assignment like this one here, so on the left hand side of something that looks like a function call E in n = E and then the right hand side, then that's translated to an update method on the F here with all indices and then the right hand side as arguments. And that works also if n = 0, so if n = 0, then that means that F() = E is a shorthand for f.update(E). So because of that, we can also write instead of sig.update(5), sig() = 5. Which is quite nice because we say, okay, sig is the current value of signal and then sig update = 5 would mean the current value of signal after this assignment will be 5. So in both cases you can read sig() as current value of signals sig. So now you might wonder, how does a signal var differ from a regular var? These signal variables look a bit like mutable variables where sig() is simply the referencing and that would be assignment but there's a crucial difference. We can apply functions to signals which gives us a relation between two signals that's maintained automatically at all future points in time. No such mechanism exists for mutable variables. Here we have to propagate all updates manually. So to illustrate the difference, I'm going to write down the same sequence of operations once for regular variables and once for signal vars. So here's a list of operations. I define a variable x to be 1, I define a variable y to be x times 2. And then I set x to 3. Now I do the same thing with signal vars. So the analog here would be I define a signal which is a signal var (1). I define another signal y which is the signal that is x times 2. And I update the signal var to be 3. What is the value of y at the end in each case? So here we would have clearly y = 2. And here we would have there, here referenced y is 6? Because the variable x is now at the signal 3. And y always maintains its relationship with that signal to be x times 2. So that nicely demonstrates the difference between regular variables and signal vars. Okay, let's do an exercise. Let's repeat the bank account example of the last session but with signals. That means we want to add a signal balance to bank accounts and then instead of having the consolidated subscriber, we want to define a function consolidated, which produces the sum of all balances of a given list of accounts as a signal. So the interesting question then is whether there were any savings compared to the publish/subscribe implementation. So here we have entered the previous nonreactive bank accounts or it's just an imperative object with a private variable myBalance. And the only thing I've done compared to the previous versions of bank accounts is that I have added a method balance that allows to inquire what the current balance is. But otherwise it's still the same as before deposits something into the account, returns a unit, withdraw something. Now what we want to do now is turn balance into a signal. So it should be signal [Int] and that means my balance would also be a signal and it should be a variable signal. So we don't need a var here at the outside but it will be a signal.Var of Int. And that's initialized to 0. So we can roll the type and initialize that into one and write that. Okay, so now what we have to do is that at each point when we want to know the current value of a signal like balance and my balance, we have to dereference it. So when we inquire what is the current value of my balance, we need the parenthesis here and if we update my balance we need the parenthesis here. Same thing we're taught here. So here is an inquiry that put the parenthesis, here is an update and an inquiry, and finally we return the current value of my balance. Okay, so let's do the next step in identifying the consolidated method. Here is its signature. It takes a list of accounts and gives us back a Signal [Int] that at any point in time tells us what the total balance of the accounts is. So to implement consolidated what we need to do is define a signal where we go through all the accounts. Take the balance of each or there will be a map, And take the sum of the results. So we can test this by setting up let's say two bank accounts and performing the consolidated bank total in the C signal and asking what the signal is. So that gives us two bank accounts a signal and that signal is initially 0 because all the bank accounts are 0. So let's deposit something into account A and ask what the signal is. So it's 10. Let's deposit something into account B. So now the total is 30. Let's withdraw something from account A. And we get an error. So what the C say here it's as assertion failed. Cyclic signal definition at the line 74 is when we last called it. So at this point here. So why would we get a cyclic signal definition when we write something like this? In fact, our error was that we overlooked an important difference between the variable assignments such as v = v = 1. And a signal update s() = s() + 1. The first makes sense but the second doesn't. In the first case what happens is that the new value of v becomes the old value of v + 1. But in the second case what we did here is we try to define a signal s so that all points in time from this assignment on s is one larger than itself. And that obviously makes no sense. It is indeed a cyclic signal definition. The definition of the signal depends on itself and that's of course forbidden. So how do we fix this? Well, we do the same what we have already done in the deposit method. We get the value of the signal beforehand. And then we use that value in the subtraction. So what we see now the sequence of action is okay, let B be the signal my balance at this current point in time only not all future points in time. And now define the next value of my balance at all following points in time to be B- amount. So now it makes sense. Let's see what consolidated says. Yes, it gives us the right value after the withdrawal. So here's another exercise for you. Consider the two code fragments here and here. They look very similar. Are they in fact the same? In particular, do they yield the same final value for twice()? Yes or no? Well, let's see what are the differences. The differences are here, num is a value and whereas here it is a var. And furthermore, here I did a signal update num = 2. And here defined a variable number to be a new signal 2. What is the value of twice after each of these sequences? After the first sequence, the value of twice will be the value of num times 2. That's the relationship that we have established. And the value of num at this point will be 2, so we will have twice() = 4. After the second sequence however, the value of twice() will still be 2, why? Well, because twice is linked to this first signal. What we have done in the second case is we have to find a signal var with value 1 and called it num. So num is a reference that points to the signal var. And then we have to find twice to be num times 2. So it's that signal var, so twice would be the signal.var of the num signal times 2, where the num signal really points to this one here. So we said whatever that signal is, the twice signal is that signal times 2. But what we have done here in the last statement is we have now defined num to be a new signal var. It is initialized to 2. So num now refers to this different signal, but the link between twice is established to the signal that num referred to previously. So twice is still 2, even though num points to a new signal, which has nothing to do with what happens over here. So the answer to the question is no.