Now we have a system with main and drivers where drivers are responsible for making effects happen. If you notice carefully, we only have effects that write something to the external world, we're not yet reading anything from the external world into our application.
Eventually we need to do that. For instance, say you need to read from local storage or you need to receive user events such as clicks. All of these are read effects that the main should be able to take in. Right now main is a function that only returns an output but it doesn't take any input.
Also notice that drivers are functions that have an argument, take that input, but they don't return anything yet. That's because the output of the main is the input to a driver. We're going to have to have the opposite, where the output of a driver is the input to main.
I'm going to call this sources. That's our input to our program. It allows us to read from the external world. We're going to have to return from the DOM driver a domSource. We're going to see later how to create that domSource somehow.
Sources and sinks are a name that come from dataflow terminology. Basically, source means an input or a read effect. Sink means an output or a write effect. It makes a lot of sense here for our main, where inputs are things that we are going to read and outputs are things that we are going to write.
For instance, if you want to read clicks happening on the DOM that should be available under sources.DOM and we're going to call that a click stream. The click stream will be created by the DOM driver, and that's what here should be the domSource.
We can create that with fromEvent document and type click. This will give us a stream of clicks happening on the DOM.
Now as you see, the DOM driver takes an input and returns something and also does the main taking input and return something. We need to plug these two together, DOM driver and main, and we do that in the run, just like we had before.
I'm going to simplify this code just by a hard coding it for now to keep it simple. We know that sinks.DOM has our messages that we should write to the DOM, so we're going to call the DOM driver on that.
We know that the DOM driver now returns something which is the domSource. We want to pass the domSource to the main function. I'm just going to pass it like that.
Let's try to simplify this problem by writing here comments that b is f(a) and a is g(b). In order to create b we need a, and in order to create a we need b. As you can see there is a dependency in between these two parts. That's actually where the name cycle.js comes from because there is a circular dependency between these two parts.
How we do that with streams is that first we're going to create a fake DOM sink and that's going to be extreme create. Once we have that we can pass it here to the DOM driver, fake DOM sink. Then we get the real domSource.
Once we have the real domSource we can get the real sinks. Then we can say, "Fake DOM sink please start imitating the real DOM sink," like that. This is a method in extreme, which mutates or changes the behavior of the fake DOM sink.
Now run is able to plug together the main function with the drivers even if there is a circular dependency between these two parts. That means that we can get the input one to be the output of the other and vice versa. It means that we actually have a click stream here now that we can use in our application.
We're going to create a restart feature in our app by applying map each click to this counting part here, like that, and then we can apply flatten. We're also going to start with a fake click just so that initially we restart, which means just basically start. This will be able to create a restart functionality, so that once I click it will restart the counting.
Finally our application can read and write to the DOM. We achieved all of this with some messy code here, hard-coded inside run but we're going to see how to fix that later.