 It's nice to see you all on the Haskell Meetup. We have an extraordinary meetup today, Andreas will show us how to code a game live in Netwire. It's all fine-to-reactive programming so I can tell that it's pretty interesting stuff. And for those that want to join us for the mentorship session, I would recommend that you come one week from now on the 1st of August. There is a mentorship session for young Haskellers or any kind of Haskellers in Hacker Space so if you feel that like intermediate but you still want to touring, I'm sure that me and my colleagues would be very happy to tell you everything you want about Haskell and hopefully start your projects. And if you already have projects in Haskell, then please, please contact us and tell about these projects here if you may. So, Andreas? Cool. Yeah, so first, who knows about functional interactive programming? Who's heard about it? Okay, who's heard about arrows and controller arrows? Okay, it's the same crowd. So hopefully this won't be too confusing. It's probably going to be a little bit fast paced but it's also going to be quite interactive so let's see how it goes. So functional interactive programming is basically, it's a way where we write our programs where we actually incorporate time explicitly. It also allows us to write our programs in a very declarative style and what that means is that we can actually focus really much more on what we want the computer to do for us instead of how we want the computer to actually do it. So think of saying move instead of x equals x plus 1. Superficially we can compare, we can think about the reactive parts almost like the observer pattern in mature familiar with objective oriented programming where an example of that is if you have an excel spreadsheet and you have a cell that says this cell is equal to this cell and this cell, if you change one of those cells, this cell depends on if we'll actually react to that change and update this own value. More formally we're modeling behaviors and we say that behavior is actually something that's continuous over time and at discrete points in time there will be events and we can react to those events and what functional interactive programming is, is to set up a network or a system of behaviors and how they react to each other. I'm going to be using this, this library called Netwire, it's by this guy, however you say that. His package is on package. We will be modeling behaviors using his derivative wire and that comes from when we talk about functional interactive programming we say that it would say behaviors or some call it signals and a signal is transmitted on a wire so and we have a network of behaviors so Netwire and event is the end. This data type is a very fundamental part of this library and it instances a bunch of interesting type classes. Most interesting is Arrow because this allows us to leverage the syntax and the functions of the controlled Arrow library. Further beyond behaviors and events we can also say that the behavior can actually produce or inhibit and this is a switching mechanism within this framework where once a wire stops producing we can say it's inactive or inhibiting and we can actually decide to use a different behavior. It will become more clear. So every wire we have is an Arrow and Arrow is kind of like a monad. I think like every monad is an Arrow but not every Arrow is a monad and it's basically a way for us to say the basic model of Arrow is that we simply wrap our functions f and it creates an Arrow that simply takes an input and it gives an output. Very basic abstraction. So that's the basic model and also how we wrap it. Kind of like return. We can compose Arrow so if we have an Arrow f from b to c and an Arrow g from c to d we can compose it to make a new Arrow that goes from b to d. Very basic. Kind of like function composition. I won't go into detail about this but basically we can also do partial application and this is kind of interesting because it allows us to keep and remember the input to our functions. So imagine that we want to say you want to apply b to f to get a c but we also want to remember the b value that I've actually put in there. It's very difficult to do but with this sort of partial application if we apply the same value to both inputs we'll actually remember what we gave f. You can read more about Arrow so it's very interesting. So the basic functions is what we see most is Arrow which simply lifts the function into Arrow and we have some other helper functions as well to operate. This is the composition, this is the partial application and this and we will see as well in the code which is basically to have an Arrow from b to c and an Arrow from b to d. We can get a new Arrow that goes from b and gives us both the outputs. It's very convenient. Netwire provides us with a bunch of default behaviors that we can leverage and most interestingly is we actually have like a function called Timer which is just as you might imagine it's a value that is strictly increasing over time and I guess I should say as well that wires are locally stateful so that's why we can have values accumulating in wires. So time will simply output goes from a to t much like an Arrow from a to b. This is why it takes a space and it gives us t's where t here is the time. We can have wires called four and this wire this function given a value t which is a time amount of time. It will give us an identity of wire that reads days and gives days so identity and it will only produce for t seconds and it will inhibit and if we then so like we can choose to switch to a different behavior. Is t a free time? Yeah so this is a bit simplified in terms of type signatures so it's time whatever that means to you. We can also lift normal functions so this is where wire consumes numbers and outputs the number double continues over time so it's not you know applied it just continues behavior. We have events and the way it works is event is imagine it an event exists for such a short amount of time that we cannot observe the value of an event so if we want to actually read the output or the value of an event we have to hold it over time so given an event a this whole function will continue to output the value of the last seen event kind of like a step function if you imagine something event 0 and then later event 1 it will make a step to the new value so similarly conversely if we have a continuous value and we want to create events from it we actually have to sample it so for example we can use a function periodic which will sample the continuous input a every t seconds and wrap it in an event for us and examples of this that we'll see is this standard noise function which simply takes a t and interval as a random seed or a seed number for the generator and it gives us a wire that does not depend on input but gives us a random number every t seconds questions cool oh yeah i would like to ask what is the event type is it just maybe or the event type yes which is it's actually no event or event okay the data event equals no event or event 8 this is the switching mechanisms we've saw so this is the type that should be wire a to a but given two wires of the same type it will produce a wire of the same type so with the way we read this it will this wire combined will behave as a until a inhibits in which time this arrow will behave as p and if v eventually inhibits the entire wire will inhibit so we will use this to build this very stupid little game um just to give an overview what you have by having mine is simply this random level that's being generated like a cave structure the player is traversing at the same velocity as the camera and gravity is pulling us down it's accelerating us downwards and if we press space we will be going upwards so this is big enough for people to see so i've cheated a little bit it's kind of from scratch we have a bunch of imports that i don't want to go through live we have our parameters that you saw in the screenshot or the diagram i showed you so we have a screen width screen height and some scroll speed this is the game this is what we need to produce for our for our render so to actually put something on the screen it's a very simple tuple that i've put here and by the way i should caveat everything this is not like best practice how you should do household this is how you cram as much as possible into 45 minutes so to don't take advice on how to like structure your data types from this is purely a type synonym for including the player position the x quarter of the camera and two lists of rectangles that we're going to use to represent the ceiling on the floor of the cake i have a type synonym that gives us a wire prime from a to b that actually hides a bunch of stuff that you have to know if you want to use network but for the purpose of this tutorial it's not necessary but you can see we have stuff like pastime monad fractional monoid blah blah blah maybe the most interesting is that this is the part where we actually explicitly talk about time in our program so s is taken there is is s is a session so that's actually how it works we're actually generating session and session deltas and then we then step through the wire to actually produce to get to actually get output and this void here is the value with which we inhibit so you can actually inhibit with some information but for this tutorial we'll just inhibit with void so this is the wire we need to produce we need to have wire it reads sdl events and sdl is sdl event is a system event it's different from just event so sdl event is something coming from the system so the wire reads the system events and it just gives us a game couple i don't have some some stuff like loading assets from this setting up the main function main loop but you can see this is just uh yeah it's just going through this calling this game function every every iteration of the main loop and we'll have some rendering stuff sorry can you with the main set sdl iteration what exactly does that it doesn't really matter because it's kind of tied to to fsl in the specifics of that so what's what's important to notice this function is being called every iteration of the main loop and that's what we need to supply so you get an sdl event for every buffer swap i mean if you so the way you would do this in c-programs is a while and you wait for an event from the system and once you get the event you feed it into to your like move player function for example and you somehow synthesize events like if i don't press any button right you still want to refresh the screen obviously yes so can you can you can you i really don't want to get into i mean the rest is going to be just just just combination of arrows right but okay so what is your question specifically um i think what i want to know at least is you do get events for for for every frame right the sdl says please render the next frame you get an sdl event that's called render video something no i still i think it would just send no event like if you don't get any event it's will use um as soon as the event of sdl i really don't know how sdl works it doesn't really matter for the purpose of the tutorial it's an implementation detail you can use any rendering library you want and or any way to pull events from the system i don't think it's important for the tutorial oh so you mean that you you need to wrap this wire with some loop that actually renders these frames it's not sdl that gives you the heat no it's it's not as though it's just as though the sxr of the rendering it gets the event from the system it says no event event some key press whatever you just have to react to the looping will happen regardless even if there's no event so to get an understanding of how i'm going to use this uh procedure e so this is similar to do syntax for monas but it's for arrows so we can just define some constants let's say we have a play position as a vector and we return this value as a tuple that we need so if you see everything's okay that means it compiles so we can actually run this and you'll see what we start with so this is it we just have a stupid helicopter to our group and nothing happens and then the internal state is like okay so when you run like one it when you crank it for one frame's worth of evaluating your network so do you get back something which you that really that doesn't matter so the way we think about is something is continuous over time we don't really want to think about looping or no i talk about the outside view yeah i understand that inside we will have this nice frp thing that is you know your basic frp setup but i'm just asking when you when you run this for one frame right obviously the next time you want to run it you want you know you want it to have the outdated state from the previous frame right so they get back it's in the presentation what does it mean to have one frame and a continuous but i mean it but in your main function right you are doing it in some sense praying right like you don't have to be defensive about this that's not why i'm asking i'm asking because i think it's a very interesting that the bit where the interfacing with the outside world happens right so can we just look at the main loop yeah because i think it will explain it okay so when you render when when the rendering happens is it only when they event happens or is it happening just because so every so this is the main loop this co-function is the main loop and it has a set of assets it has a reference to the screen it has a session and it has a wire right and then you get back an update so the first thing the first thing we do in the we call the system has there been an event and this can be either no event key press whatever screen updates screen resize any kind of event we stepped the session so this is the old frame and we get the session delta and a new session we then step the wire and this double use can be game with the session delta and we actually have to tell the wire that will have an event this is the event and then we parse the output and if it's inhibiting if the game is inhibiting we'll get the inhibit value left so we quit otherwise we have the game tuple in which case we render it we flip the screen and we're in with it with the new session and the next step of the wire and step session is also something provided by left wire or the only thing here is that wire is these two functions and the ds is the time data uh it's it's a session delta but in this case it's time and then i guess the answer to my question is that you get back this w prime which you then tested in acceleration so that wire gives you the update in network which has yeah it's correct it's really beside the point i think the the purpose of this is when i assume continuous time but of course it's not continuous this is what happens and it keeps track of the time between you when you call these two dots for the session delta it knows it's like oh it's been let's say our function integrates a continuous input value so it integrates time for example i'm on to deep about the seven eight and it knows okay this it was called time equals one and then let's call again the time equals four and it can do the sum for you so will you render as many frames as you can basically and just yeah there's no time limit that this that wire function yeah it will it will know it will know the time difference between the two frames and then it can calculate all the values if it needs to do that okay so a good start i think is to start with a scroll because and this is basically we want this to be a wire that doesn't take an input so we just put an eight and it gives us time out and we effectively just want this to scroll as fast as the camera scroll unfortunately this isn't compiled we need to say do you normally have to be explicit or can you just generate it from what the content here are these types inferrable by compiler uh usually not you often have most of the time you have to give it so this is a function that simply takes time each other times so one two three four five seconds however long it's been in multiplies it by scroll speed to give us the camera's exposition uh we can then say camera position is equal to scroll and we just give it some dummy input because it's not being used anyways and now we are actually scrolling leaving everything behind oh shit i forgot my notes will you please excuse me for like one second i'll write back the process now we can read the main actually it's not like complex when you look at it yeah maybe if we have the signature for step session and step five actually just go to the main loop anything okay we're done with the main loop i love it i think it's indicative when i get this looking brilliant nobody gave a shit about the main loop but it's good that people understand how we write this ourselves right there's no point in just using yeah yeah i know it's it's good it's good my point is that it's very like implementation specific to stl you can use whatever so so yeah so we'll do it on the next tutorial yeah we can do the main loop on the next tutorial so to generate the world we want to basically have a wire it generates uh lists of rectangles because if you remember we have this this is the requirement right this is the protocol that means it disconnected some of the techniques power we have power means power it's too much when you look at the screen oh strange your phone there's also some some characters cut out at the beginning all right so oh yeah the resource may need to be adapted to the projector because i think three sizes though so what do i do thousand two hundred i think yeah yeah something like this what are you doing can we do it yeah smaller can we just move the window this is the problem can we just make the window smaller okay advantage is that it's fun to speak it was perfect so well yeah basically we want a wire that simply gives us laser rectangles right we think if we have this we can actually start leveraging this function to generate both the ceiling and the floor of our cave so what we saw we have this standard noise generator that tends to topple but it basically needs a period it will need an interval and what else to see let's put that in the interval so this function this wire here will actually generate events of doubles at every one second interval assuming that function was probably want a wire that reads those events and gives us a rectangle amount so we should be able to simply apply the output of this to the rectifier and the type of this one will be an event rectangle now network gives us this very nice function at Q and E so if you see the types unit at the bottom this is something that this gives us a wire that consumes event with values of type A and gives us events of type B where B is an accumulator so we give us give it the empty accumulator and how to append to the accumulator so I'll write a small function about cumulus I want to accumulate in at least so I would tell it how to put things in there so so at this point this is now something that gives us an event of a list of rectangles and if I compile it you'll see it says okay it says to keep growing at one time yeah it will be a memory but for the purpose of this tutorial it doesn't matter so you just add a rectangle or yes we yes I know we add things to the beginning of the list how this being done will be shown here but this will be an ever-increasing list of rectangles but in order to get from an event to an actual event list of rect to an actual list of rect we have to hold this value and that allows us to do this now how to create a rectangle from just one double so this double here is going to be the random height of the of the rectangle we know that we also know the x-corner where we want the rectangle to be put because we know where the camera is from this scroll wire we have so they effectively we need two more we need a function that is able to take this double and the scroll double and then from those two create a rectangle so that's something we need right so again we can use the arrow syntax so it takes a double event for double and we have this two rig so we can actually get that function by saying applying that scroll and we also want the rectangles to start at the right end of the screen so we add the width of the screen to that and then so this function takes a double and gives a rect so we want this to be event double to event rect so we do the application like that and now all we need to do here is capture a function here as well as such probably something so we can now just give it screen width is also a wire no that's just so every wire is a number as well I mean you don't need to lift it sometimes no because wire actually instantiates now okay so we can say scroll plus this number because it's a fraction so we can now define our game world as a wire that doesn't really take an input that gives us our rectangles well it's a new keyboard if you want to take a look at the world of the ceiling and the floor where we can now simply use this rects function we give it an interval and we have to give it a function how to create the rectangles and uh we have to write this something quick actually let's not let's no let's just give the x coordinate we know for the ceiling the y coordinate will be zero we had the since we're sampling every one second the width of the rectangle needs to be screen width and we'll give it a height and for the floor we can actually instead of using the height for the height we can cheat a little bit and use it for the white coordinate and simply say a fixed height so the rectangle will draw below the screen but that doesn't show up when we actually render this since it looks okay we can say okay so what that looks like it's not well actually so there will be some glitching here because of some rounding errors I presume but and since we're using the same random number generator for both the ceiling and the floor they will actually be symmetrical but I hope you can imagine that this can be done a lot more sophisticated but we now have a world but what is doing the scrolling because you keep pretending these rectangles they are never growing least rectangles as they are in the x coordinate just keeps growing and new rectangles just keep being created yeah but they keep creating the larger and larger x value yeah so it comes from here scroll it's this yeah but that's that's why it's more and more to the right but where is the actual scrolling I mean the fact that it's more and more to the oh it's in the display number the renderer so this this will output a tuple where then the middle body the supple over time will just be strictly increasing and then the renderer just picks it up and puts it on the screen and really now the only thing to do is to position the player and we know for the player position it most likely it's going to depend on the input because we know we will have control over our vertical coordinate so also this wire is going to depend on system events and it will give us a vector position vector the thing with position is we can actually get the position by integrating our velocity so by giving it a base of a starting position maybe like 200 200 if we integrate velocity that will actually give us a position similar to this and so this double and just for the sake of demonstration we'll start with hard coding a constant velocity of which is equal to the camera's full speed and we say zero vertical velocity and now the helicopter should be well known because easy now we actually have to give the assistant another player's tagging along with the camera however we want the player to fall it's too easy so how do we fall we all we know is we know that we have some acceleration downwards so we actually want to integrate the acceleration so even a starting velocity have some downward velocity beginning then we want to integrate the the gravity vector which is zero in horizontal axis and let's just put 800 pixels per second per second as the falling acceleration and if we run that we will not be falling at a strictly decreasing speed so to to sort of combat this this falling effect that we have we would actually be reading some some input from the from the system so we want something that says space press actually on the space and this is actually do yeah and this is actually a case for for some other reason I have to use actually let's try this network actually gives us this function became if you look at it became it takes a pretty well I can't put it takes a pretty good A to ball and it consumes continuously input A and if ever an A that it reads matches this predicate so the predicate is true it will wrap that value in an event so this is very convenient for us if we want to generate events from a key press and what happens is it just passes through the value so that's why we have S still event and S still event here even though we don't really care about the value in the wire output this became function S sort of passes through for us so we take the event and if the event so happens to be a key down event and the key sum happens to be space in that case we'll say true otherwise we'll say false and I'll do some couple case programming similar look for up so now we have two wires to generate events to us in case we press or release the space bar so we want to use this here somewhere and as we might use we actually want to use the switching mechanism here to switch between different behaviors so we'll call this fall so you want to fall until we press space and then we want to go up until we release this and then we want to look around this is actually quite easy so press space this until function takes a tuple where it reads continuous input a and as soon as this event b happens this this wire will inhibit but it's before that happens it will just pass through this value a so we can simply say press space is a dummy value that we'll never look at and space down and for the sake of speed we will simply have a constant upward acceleration but we'll still have to keep up the camera and zero zero to the top left corner so we need to if we want to go up we need to have negative point velocity so our velocity our position is integrating our velocity and our velocity is basically falling until we press space and then we go up until we release space and then we ask for a run let's see if we press a space we actually start going up but we have no collision it's actually quite easy to add so the final function that says given a point a rectangle take the rule this will define a function called or a variable where that simply reads our position our rule and gives us a loop to lift it into a wire by using the arc position and to list and if any contains the point or a point so we can check for collision by feeding this player so when so what happens here is we check for a predicate so this thing will produce as long as the predicate holds true so as long as collision is false this will actually be producing which means we will move on in this sort of code whereas if this one inhibits the entire game will inhibit which will in turn in the main loop create this this less value in terms in which we will under which we will quit so at this point if we now collide we will quit the game yeah that's kind of it i have like a little addition if you're interested otherwise i'm happy to hand over to sunke see the addition since sunke is not ready at the moment i think cool let's just do it it's pretty fast so i think i'll have to yeah that's fine so let's assume we want to have some particle effects so let's say we just want to have smoke puffs showing up after the helicopter and you can imagine like adding how to do more particle effects whatever but let's not have a smoke puff and all that needs is a position we'll add all this smoke puffs to our game state one of the parts in the magic where i actually have some so we didn't actually change anything in the game so far yes we added this empty list of kind of particles that we want to have and it's just empty list now so so if we want to have a wire it's the smoke puffs and this one will actually have to read the position player and out will be a list of particles so this is this is in addition this i'm actually have a sheet function here it's called managed wires yeah so this is not provided by the library but it but it does it basically maintains upon it maintains a collection of wires instead of maintaining a collection of values it actually maintains a collection of wires and it gives you the output of those wires and as soon as any wire in this collection of wires inhibits it will get removed from the collection that's it so we know we're getting the double from from the play position and we can use this wire to create at that position so this is a wire that creates this continuous smoke puff given the play position to just produce smoke puffs but we actually want this to happen at discrete points in time so we have to sample it with a period so i think 0.09 was a good one for them so what will happen now is nothing that's all we see so we'll feed uh smoke to and we have to give the play position and now we should see the smoke puffs but they last a little bit too long so we can actually in this uh place we can say for 0.5 seconds show us what so instead of the wire lasting forever now it's a it will inhibit this wire will inhibit after 0.5 seconds and we'll get removed from the collection was the type of this four company here so this is this is just the identity function so for 0.5 seconds it will let this wire through and then this entire wire will actually inhibit after 0.5 seconds and when it inhibits manage why i will remove it from the collection okay so okay so it's not just an arrow but is it some kind of arrow of line that's okay that that's a huge size in the it won't show so does that work does that mean that wire is not just an arrow but line it's also applicable in the bunch of stuff no not applicable apply right i think of course it's applicable i think i think it is because you have a the reason i i'm asking is because you have here a function which given a value returns a wire right and then you leave that like you give it to the code so it's okay you have this lambda which maps a value to an arrow mm-hmm right and then so this is if that it are if it is a wire which goes from the player position to a wire of right so this is this is this is a wire that is producing a wire yeah exactly yeah and then i'm sampling the the wire is producing wires to generate an event wire and then this function will exit we'll just set that wire so manage wires is horrendous is like like import control unsafe event so it doesn't it does a bunch of stuff in the back on but but okay but okay so this is my understanding the question is wire an instance of arrow of line yeah i don't know i was trying to check uh okay uh no which is why you need to do this unsafe stuff instead of just i do not know so the code is over a year old so i don't remember thank you most yeah but i mean but you see why this is all about arrow of fire right no how because you have an arrow which produces an arrow as you want to leave that i mean you want to squash that into an arrow or the thing which is exactly what arrow of fire gives you and which is which is exactly where arrow and monad meets that's why maybe that's why manage arrows is not there so yeah it takes this particular one and maintains a collection of arrows that are so what it does is it maintains a list of wires and then it steps each of those wires and either just keeps it in the list or removes it that actually looks like the magic maybe it is i don't know i'm just using this library i'm not uh yeah maybe that would be interesting to look into if you feel like it i don't know so yes that's it i find it fascinating that you are actually so little to the streets like inhibition i think the only thing that i've seen compared to to other reactive programming stuff is this inhibition and letting the objects kind of die yeah and it starts being so much easier please yeah i mean i think i think the fact that you can write this is probably the most i mean there's a lot of stuff that's happening but in terms of declarative style like this is to me pretty nice in that you can write this and actually i don't think you you would have any memories because for the k for example we just take the i think first 10 or yeah of course of this 10 rectangles and you know so this is not like i have a different branch this is like a slim down version for this purpose i think the became became function actually has a memory weakness when i was doing my profile so but that i think that's a net wire issue i'm not sure but i guess you could left compose that with our const unit anyway in which case but that could happen but then nothing of the original stream remains except for the timestamp maybe i don't know i could do it your way ahead of me yeah so that may be stupidity it's it does provide a fine show like different like help with that so that that could could be the case cool done