We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
Analysis Summary
Worth Noting
Positive elements
- This video provides a detailed, unedited look at real-world functional programming problem-solving and REPL-based debugging.
Influence Dimensions
How are these scored?About this analysis
Knowing about these techniques makes them visible, not powerless. The ones that work best on you are the ones that match beliefs you already hold.
This analysis is a tool for your own thinking — what you do with it is up to you.
Related content covering similar topics.
Datomic Cloud - Datoms
ClojureTV
The Taming of the Deftype Baishampayan Ghose
Zhang Jian
Create a password manager with Clojure using Babashka, sqlite, honeysql and stash
Daniel Amber
Parallel Map in Erlang
BEAM Channel - Erlang & Elixir
Testing with ExUnit in Elixir
SmoothTerminal
Transcript
bomb here we go five four three two one hello and welcome to my little video on um exorcism thank you very much for joining me or watching uh afterwards my name is John um I create a website called practically which helps people learn closure from my own experiences and from the community and today I'm going to do some closure exercises as part of the summer of s expressions and so there's already been some introduction videos into closure so I'm gonna dive right into the code because I think the best way to understand closure is to actually start using it and experimenting with it it's a very Dynamic language so it's very easy to do so there are there's about 70 or 80 well 86 exercises uh in total on closure I've done some of these not all of them so the green ones I've done and the blue ones I've still to do and we're going to cover four exercises if I've got time uh starting with RNA transcripts and a similar one which is nucleotide count and both of these will cover kind of some of the iteration of a Maps and uh defining a data structure and some interesting functions from the closure core Library which there are about over 700 functions now to learn you don't have to learn them all at once but they are over data Centric as disclosure so there's an awful lot there to get going with and so it makes creating your own specific code very quick and simple so let's have a look at RNA transcription so the Crux of this uh problem really is we want to convert from one thing to another the first thing is DNA and we want to convert to RNA strands and it doesn't matter if you don't know what those are because we are actually given a nice little conversion table so if we have a DNA DNA nucleotide which is G then we can convert that into RNA uh the C nucleotide so we've got this nice little mapping that we do so basically we want to be able to write a function that can use this it's almost like a state transition and we map each character of a DNA sequence that we're given into the equivalent RNA sequence so let's dive into the code I've already downloaded these projects using the using the exorcism command line and it's given me a project here I've got project open I'm using neovim but there are many many editors you can use for closure and it's a fairly straightforward project structure I've got source code under source I've got my unit tests under tests and you can see the test code is kind of matching the the naming Convention of the source code so we've got RNA transcript an RNA transcript test that way all the tests referring to the source code is in its equivalent test file and there is a there's a configuration file here which just defines the any dependencies that we want and there's a test Runner we can use I also have in my own test Runner I can set up and closure is kind of built into the uh closure CLI tool that we're going to use to drive everything so let's just hide that so we've got the mapping here and we've got a function so this is kind of the starting point we haven't actually got a solution yet and in order to be able to run the tests we need to have a function to evaluate uh so we've got this we're defining a function here called two RNA and at the moment we're just returning well we're returning nothing this is the argument we're not taking any arguments yet and we're not returning anything either by default to function will return nil if there's no other value to return ah so let's have a look at the tests uh so we can see from the tests here that each test is calling this to RNA function and the test code is is pretty straightforward it's again we've got this namespace that defines like this logical grouping of our tests right respective to testing this RNA transcription namespace and we're including a library called closure test and specific functions from that Library we're only going to use deftest and is deftest just defines a test and is is is is is is is an assertion and a session is defined by is so these both functions from that library that we've just included in there and we can just use them straight away and so we're defining a test with the name and each test has its own assertion you can have multiple sessions in here as well if you want and we're basically saying uh we're defining these predicate and we're saying this is our expected value and we want to and we're going to call a function from our namespace under test with an argument so if we call this 2 RNA with C we should get a g so we need to make that work somehow uh so this is the kind of main body of my code uh and this this does compile so I can evaluate this uh what I do is start a rebel which is like the uh runtime environment so this runs on my closure code so I'm in the root of my project I'm going to run a closure Ripple you can use clj which gives you a very simple UI um I'm going to use something that's a little bit more interesting to use uh sure and this is called Rebel so it's a rebel with Rebel this gives a nicer user interface you kind of cost or do this all in the exorcism uh uh editor but it doesn't give you kind of that Ripple or feedback which is very nice to have so I can actually Define I can actually Define closure expressions in here and it's actually giving me uh hints and documentation about the the function calls and what to uh what arguments to give things it's quite nice uh so let's do something very simple just to make sure the Ripple's working uh so here I'm going to call uh at my map function yeah um I can't type anymore there we go and it's making sure that the it's showing me that the parentheses are matched so here I'm calling map function which is going to take each value in this collection and apply this function to it and this function just increments the value by one so if I press enter it evaluates the expression and I get my results there we go so rather than type everything into the rebel we use our editor that's connected to our Rebel running uh where did that go let's see here we go so that should be bringing the rebel now yeah I didn't want to do that we go [Music] I'm confusing myself now there we go there we go so we're now connected to the rebel that I was running uh from the editor so I can now evaluate things in the editor sent it to the rebel and we get a result so I can evaluate this namespace which just defines it's just basically loads this namespace and any require functions so we're requiring closure string so I've had basically added closure string the library to this namespace and I can do the same thing with this function foreign this function into the namespace and so now I can actually call that I won't actually do anything but I can call it if I want to do so I can just call that with two uh RNA doesn't take any arguments so if I evaluate this it's not going to do anything too exciting it's just going to return nil if I put in a value one it'll return one I just need to reevaluate that again there we go a nice one so I can dynamically develop the code very quickly by changing it evaluating it and seeing what it does and so it's a very Rapid Way of developing designing code and to order in order to keep a separation between the code I'm writing I'm coding I'm going to eventually ship and the code I'm still experimenting with using this comment expression and so everything inside the comment is is not going to be run if I evaluate the whole source code file so if I run tests if I just run the program these things are basically essentially commented out it's like a a line comment on steroids but it allows me to basically go in and still evaluate the expressions but do so while I'm well I'm just experimenting and then copy them into the main part when I'm ready so how do I Define I represent the data closure is being a very data Centric language then it's uh it's quite a focus of it to think how do I represent the data and there's quite a few different data structures built in Roger looking at lists so around bracket represents a list so the list with elements in there and the the list is special because it treats the first element as a function call and everything else as a um as an argument for that function call you can use the quote to um just treat it as data but most of the time we use lists to call functions I'll Define functions in cut so here we're defining not a function as such but a name a symbol it's going to have a value and we can give it a doc string and the the value we're coming up with is we're just defining this hash map and so hashmap is uh yeah it's like a dictionary and python in other languages basically a mapping so we've got a key which just happens to be a string and that key is associated with another with the value which is another string and that's so we've got four key value pairs in our map and uh our map has to be balanced if we got rid of one of these things then we'd have a missing value for key a oh that's good so that my linter telling me that I've got something missing um so we can very easily create this stage transition by saying if we want to know what G should be transformed to we can look at G and it's going to return C from the hash map um so that's what we're doing here we've defined we could have a very simple function that is uh to RNA and it takes a nucleotide so just one character and we get from the DNA dictionary which is our name that we defined uh the nucleotide so if we evaluated both of these then I can call to RNA with a let's call it g because I know that's going to be C and if we evaluate this we get a result so it's a very simple way to create a dictionary and yeah basically have a look at table State transition as you wish um if we're going to do this uh normally I'd kind of create a I create a function with two arguments the nerd actually pass in the dictionary into the function as well this makes it more pure function as it's called because it's taking all the arguments it's not pulling in any arguments from outside whereas the DNA dictionaries is kind of using this namespaced Global um name Global symbol and pulling that in uh to so there's kind of a bit of a side effect there it's not a big issue in this little challenge but normally you would kind of take this approach where you would give a function all of its arguments and then the function itself is always deterministic if you give the same input to the function it's always going to give you the same output and this works as well so if we can define that yeah so we get G um so that's okay for a single sequence but what about if we want multiples if we've got this string there's a really handy function called map so if you space l and H for the destructions so this basically is going to return a sequence by applying the function to all the items in that map so we're going to take it's a map it's going to take this function uh uh this is just an example this is not part of the solving the channel challenge um so we're going to map this function over these characters and this function is basically just an anonymous function it doesn't have a an external name so we're using this function in line This is called a Lambda function and basically this is converting each character into lowercase so lowercase takes a single character and so this is what we're passing in passing in this function takes an argument character and we pass that character to the lowercase function and hopefully that does a conversion so that converts all of the characters into the lowercase equivalent let me do that as a comment uh there we go so uh to give it as a reference and so we can do the same thing with our uh with our nucleotides so we've got our DNA we've got a dictionary and we can map that over by passing each nucleotide each character the same thing because at this time it's going to convert it to RNA and we can see we get nil nil nil uh all the time so oh there's a bit of a problem uh but luckily we've got a rebel so we can investigate what that problem is and so we do need to uh refactor if we actually look at what the output was of this um so we started with a string of uh characters uh and we ended up with a sequence of individual strings and so um it's it's converting when we're doing the uh when we're using the map it's treating each of these elements in the string as its own value so it's pulling out a and when you pull out a from uh the string it's going to be a character rather than a string so when we're actually doing the get function from the dictionary um we're actually passing this nucleotide we're passing as a character so we actually need to convert that to a string and there's a built-in function called which converts pretty much anything into a string within reason anything legal enclosure into a string um and so now when we do this uh then that will uh that should work um I think we can use this again now we yeah so now we've got our characters instead of strings I do notice I'm kind of closure is by nature it's it's read in order but when you're in the rebel you can kind of as long as things are evaluated you can call them and whatever was evaluated last um but most recently so here's my DNA RNA definition I just updated that definition and now it's using that definition when I call DNA to RNA in this expression so now we get our so we're getting our converted characters but again it's still a sequence and it's not a single string if we looked at our test then we can see it's actually looking for a string another sequence of sequence of strings so we need to do something about that as well uh that's another refactor um I've already done um so uh I can use join to to join things up so I can do if we take this [Music] and we do closure dot string joint that's our expression uh so that we've just copied the the result from there though it's it's complaining that string is not a function call so this is if I leave it as a list it's going to complain that this is not a function call and an error but I can use the quote uh symbol which is just a shorthand for uh quote and say if I quote that to be there you go so that will restrict the that sequence of characters as a day treat won't try and evaluate the the U there which is which is nice so if we do that uh but normally you would just use the actual quote character um because it's a simpler and uh looks nice we evaluate that now we can see we get the single string with all the characters in so if you put all that together uh in this new to an r a function definition put a nice description in there so we take the DNA strand we're going to join the result of mapping DNA of RNA um uh DNA dictionary we're using this short form of a function here so um uh yeah so previously we've used where is it there is it yeah we use this we've used this form of expression to define a function so a function takes one argument and we can replace that with a simpler form of the same functions this is still an anonymous function but we just use this hash uh sequence let's put them in the right place up there so these are kind of equivalent I missed off a and there it is I've broken it now uh yeah I'll just leave that there so this is a there we go so this form is the kind of full form for a function an anonymous function that we use in line and we can use this simpler version DNA to RNA um so basically remove it we're dropping the the function and the argument and we're using these placeholders for the argument so percent is basically the argument and it just gives it the code a little bit simpler and uh it's something to get used to but it's quite nice to use so we're basically taking this function here and applying it to each element in our DNA sequence and we should get the results uh boom so if you use a test example would I do something wrong there we go um something's not quite right did I mush these up I don't know uh let's go back to that okay so yeah so if I map this over here you can see we're getting some issues still because uh X and F are not part of the uh not part of the dictionary so we actually get Nils in this place so we need to do some error handling and um we can basically just throw a a function so in the end that's just basically dipping down into this throw or some throw assertion thing here so we can throw a we can use the underlying Java code to throw in a session so this assertion error is from the underlying host for our closure runtime which is using Java underneath is using the Java jvm underneath um and so uh we can use some of those function calls so this is basically creating insertion error plus from java using this dot notation you could also use uh like a basically creating a new assertion error object I'm passing that an argument and then using the closure throw to to throw it out uh because if we if we include this in our code we need to make sure this is not actually being called so there's a nice kind of little technique where we use this or function uh and so we basically do an awe of um the we check to see well we convert our uh on our DNA in here and if that works then we don't it the all will just stop there if that's if that returns a True Value then we don't need to do anything else um however if we uh if we do have an error then we can uh oops [Music] if we do have an error then we can put this throw into here so if convert DNA returns any uh false values which could be nil or um or false the Boolean false then it'll throw this new session over and uh that will cover the bases for um the characters that are not in our dictionary so our final solution is uh here so I'm going to copy that and put that up into the top of my code to replace that one boom I just playing games to me today so we've got our map um oh there's strings um oh yes um yeah so rather than convert the uh the nucleotide into a string each time when the map is extracting from it so when this map function is going over each of the each of the nucleotides it's going to convert it into a character so we may as well just use characters in our mapping so it's going to return a character so we're going to look up a character and it's going to return the character uh and that way we only have to use one string function to join the finishing function at the end um so I put my day trader on place there we go no why is it complaining um I think I've missed something off let me just check live coding you also have some something that doesn't work when you're live coding uh source code poop oh um did I DNA to Ireland oh is it still think it's a function no that's not right I shouldn't be doing that uh let's see if it works let's try that so we go to the little test run out it's going to run all tests tell me whether the code is working or not we can also submit this to uh exorcism and it should work why is that taking so long there we go so the tests pass there we go um oops and uh I have all the tests kind of working in here so they're all passed on here so this is basically yeah this is the same as what I've submitted to uh exorcism there we go cool so that's one down let's look at another one so this is nucleotide count what do we do for here uh we got another string and we want to find out whether um well how many of each nucleotide is in the DNA sequence essentially and if there is a an incorrect nucleotide in the sequence then we throw an error all right so we're doing the tide counts and you can do all the testing and running of the report from uh from an editor you don't need to have separate terminals up north on like I've got here um I'm just used to using the command line myself oops let's take that so let's run the wrap all in here again I'm just in the root of the nucleotide count project which I've downloaded let me do closure and so closure is the command line tool that runs uh closure project closure code and we can give it what we call aliases to run different tools as well so here I'm running the Ripple tool and I'm going to equip from that all right so again this is just the project against just the same uh some of the exorcism projects uh because they're these are older versions they've got the project CLA clj the one which is the lining in configuration for these uh whereas the depth even is the closure CLI configuration uh essentially they're just defining the uh the dependencies that the library uses and any other tools that you're going to use with this project the code itself is is the same whether you use lining in or closure CLI so let's fire up Astro which is uh my configuration for neovium I can open the source nucleotide Source node test nucleotide count there we go so let's look at the test and we can see so it's the same setup closure test Library we can see that we've got uh two different functions here so we've got this count of newly tides in a strand which is taking a single character and a string that we're looking for and then there's this nucleotide counts which is just giving take which is just given a string but it's expecting uh a a data structure back inspecting a hash map of um keys and value Pairs and the keys being characters in this case whereas uh nucleotide strands expecting a an integer value so there's two different things here this one's a simpler return value we're just returning a simple integer so we'll have a look at this one first uh let's go to the top of this so we've got our two functions we've defined so we're going to try and solve this uh counter nucleotides in strand first again I've got my rich comment form and I'm going to do some experiments with uh I did start the Ripple in there yes I did okay there we go so that's my record running that's just to check to make sure it's there I don't really again you could I don't really use the bathroom pretty much but it's nice to kind of see some uh some of the longer output in there as well so we've got these two functions and uh again how do we Define the data um we kind of gave us um there's no mapping this time so again it's just so this time it's just simple data structure we want to know what are the valid nucleotides are because at some point we need to check whether something is valid or not and if it's not valid then we can throw an error so would you find this with this is our starting point a nice impact closure is you can kind of come up with a data structure test it out evaluate it in the report I'll see if it works and if you need to change it then you just change it and reevaluate it and uh and see see what happens so it's very easy to experiment um so now we can test to see whether something's in there um so we're using the sum function so sum takes a predicate so we can use this Anonymous function like we've used before so basically this is a function and the function body says is equal G the value we get from uh our valid nucleotides so basically it's going to check if G is even within our nucleotide data structure and if we do that you can see it's true we could also wrap G in a set and we could use set as a predicate as well a little bit more fancy but it's kind of a nice shortcut as well uh um so um I best off something I'm like okay right yeah so we can count um yeah I'll be something up here yes so I was going to uh count the I need to cut the functions first don't I I missed a bit off there we go did I did I do that later on uh I think I must have deleted that bit oops apologies um so let's do this so um if you've got a string we can count uh how many things are in string I think there we go there's nothing in there if we put um an A in there then we can count those and so we can use the you can use the get from a string uh well we use our valid nucleotides can't we uh so get from and then is there a an a Let's do an a h [Music] did I do that right I want to do it wrong foreign [Music] oh yeah sorry that's what I was gonna do um so I don't want to get I want to um if I need to know the the total uh I need to know how often it's um often it's occurring what's its frequency um is there something called frequencies in closure frequency oh there is nice there we go so returns a map of distinct items um that's four I can export the second part yeah so uh what did I do for the first part I've gone blank for a second um uh nucleotide counts let's look at the right one boom boom oh it was that one I was thinking something else oh yeah uh yes not frequencies I'm thinking of something else for now but so we got a valid nucleotides and um so we want to know how many characters are in there of a specific type so if we're given a string let's have a look at an example that we've given let's take this example from the code the test code it's always useful to start with the tests and then you know the tests will pass uh so if you've got this string oh and see how often a appears so let's let's come back to that bit so let's uh let's get out the uh this is uh so we've got a string with our Stringer oh uh so we just said we wanted to know how often uh a was in there all we could do is just get rid of everything else and say we only want a so we can filter on the string um but we need a some kind of predicate to do that so let's create a little Anonymous function well let's just do a function um so we want to take each nucleotide and then we want to uh basically say is that equal to um so these equal the the value we get from the uh string nuclei and let's say we want a from there so now we see we get a we've got two currencies so we could just do something simple like uh count and let's just move that to the it's in the right place the parents are balanced and if we evaluate that now see we get two so we're converting the original data structure we're filtering out the ones the the characters that we don't want and then we're counting how many is left um and that's nice and simple and if we've got the uh value nucleotides then we can use this throw exception to see if if it's not in there then we can throw that out we could throw out the weekly throughout an exception if we get that so we just need a and if statements which uses let's see let's do some let's do this one so that's our condition for our if and then if it's true we do if it's true or if it's false so when it's false we want to do this throw throw ball against just tapping into uh the oh there's a bracket missing there you go so if it's false we want to so it's false basically saying that g is not in the nucleotides which actually is so I should use something else for that so if it's G then we're going to use the the um the true path uh and if we were using something like X then it would use the the false path throwable um so if we do that and then we go throwable in here I think yeah so now we're getting a throwable error so that's working cool so that's an error we actually wanted whereas if we do G that is in there so we should get true we get true so now in the path we can use our count filter we can put that into the true path here there we go we get two so there's two G's uh in our is that right oh no uh we're hard coding that into there isn't it that's uh yeah we need to write a function around that uh and our function was cold uh not that I think it was called this here we go so we Define a function called that and give it an argument um let's call it nucleotide and then if nucleotide is that so we want to change that but um we want to do that same thing again here but uh oh okay uh so we've got a naming Clash here so what I can do is actually just get rid of uh the larger form and we'll just use the short form of the anonymous function change the uh the first argument that's passed um and then oh yeah we need oh actually we need the strand of Easter and to satisfy that so this becomes that now becomes a strand there we go now that's our function defined uh so in theory so if we go over to the test grab the up on these test values um and if we call um cool okay nucleotide strands we give it a Strand and then the character of what character was it using D and T this T there is a t there so let's do that's t t so if we call this um oh oops deafen it's a function not not a value ah there we go there we go we go on woohoo so we can actually put this function into our solution so we replace that one and we could go and run our tests if we wanted to um a nucleotide count yes uh so let's close your eyes so this will pass some tests it'll fail other tests so I think it's either three or four tests it pass it's not failed I can't remember which yeah we'll tell us I felt the moment did something wrong oh ah I forgot to copy over the valid nucleotides didn't I yes that was silly so it's trying to use um these valid nucleotides uh but I haven't actually defined it in the main thing yet yep it's nice where is it from there we go so grab this and I can run the tests and the rebel but it's also good to also run test externally because it's using files issues the files as they are ready to to disk rather than the evaluations you put into the rebel so obviously this should run I had to run a few tests you can also use this in watch mode so as soon as you make a change then it will rerun the tests so it's failed some tests and it's passed other tests uh yes so we haven't actually done this counting nucleotide so I would expect those to be failing and it's showing me um that rather than expected value we're getting we're actually getting nil so we know we've still got a little way to go oops wrong one um okay so that's part one so let's have a look at the second function second function we need to solve so we could map over the value over the oh that's where I was looking at it okay there we go yeah okay um so we need to return this form um so how do we do that we could use a map and map over the the string that we get but there is a nice function in closure called frequencies um and if you like sit back and think about a problem for a little time you usually refer this refer to this as hammock time it takes some time to think about what you're actually trying to achieve I'll talk about it in kind of English language and then often there's a as a meaningful function that has a similar kind of name than what you're trying to do so here if I was thinking how often does something appear what's its frequency then okay that kind of gives you a hint that maybe the frequencies function in closure core uh enclosure standard Library would actually help you uh solve the problem uh so if we evaluate that with a test string from our test classes we actually see the form is is there it's like is that is that enough have we finished have we got uh success um well the problem is what if something isn't there so if we actually deleted um the T from there we haven't got a value for team we're always supposed to have a value for each of the counts even if it's zero so frequencies does most of the work but we need to do something else um and how many accounting you're you're kind of counting from well it comes from you start with nothing you start with zero and then you start counting so what if we actually had a starting condition so saying everything is zero until we find out more information so we could actually just Define our start condition uh using a map so here yeah so here we've got a map of characters and their values so they're all starting at zero and then if we merge that so we use a merge function which is basically combines to Maps together and there's some examples there it gives us um yep so um we can take the starting position and then we get the result of frequencies so even if we use the one that's uh there without the T uh we've got teaser starting point so if we merge this on top it will update the existing characters that match uh with their frequencies uh and we still get a value for T because that's what we started with there we go so now we can just include that into the function and we should be done I think so where's our nucleotide Cuts so that's oops y okay let's run our tests and see if that actually did work I think it does I think that's what I submitted let's have a look see what I submitted I think I might have done this slightly differently in the uh let's have a look what iteration did I do oops oh I did lots of different ones in here um oh yeah I used a four as well that's another option I think the merge is quite simple because Ford again doesn't quite get you there as frequencies yeah simplifies this code as well but sometimes you kind of have to write a longer expression then you come back and refactor it in the end so this kind of shows you my journal of how I got uh there um yeah and that was my end goal there as well so hopefully that's uh did I write the file I was remember to write the file I didn't write the file oops that would help there you go uh again it's a it's a nice signage to check to run the test separately so normally before I do a commit or at least I push a commit I'll run the tests and um and then we should all pass there as well um we've got a little bit more time to do so um I was going to look at space age and bank account I might just look at space age on here actually um I had to get some mentoring support on here let's see so this was fairly uh verbose when I first did that but I iterated it around a little bit so basically we're trying to add um we're trying to find the orbital periods of uh planets in our solar system but we're given data based on the um uh the age of the Earth um so let's see I think that's that's um let's show you this in here we want to go to space age there we go uh so from the from the test it's trying to do um from this test we we have these uh individual functions on Earth on Mercury so we basically have a function for each planet so we need all these um supposed to be uh on Earth function oh I know I've already got that I just missed it there we go on Earth there we go um and so yeah what I was doing was uh you know think about how to represent the data and then um I'm going to calculate the the total basically the time the time in seconds but um uh that something is taking to go around uh the sun to work out the the same thing for the Earth um and so we basically take the orbital period of the earth which is 365 days and a half and a quarter sorry um and then given the seconds uh we can just divide the seconds uh by this value and we get our we get our results so let's see I'm not evaluating that am I but this age that's going slow all the broadcasting slowing it down a little bit um there you go uh so we've got an object period And if I can calculate the the hours minutes and years uh seconds in a year um so but that's relative to the Earth orbital period um we can kind of generalize that into a function and uh and then you get just call seconds to use uh with the seconds um but we need to do that with the other planets um so what I thought was kind of creating an orbital period section and then we have uh function on Mercury which does which basically adds in this relative Mercury orbital period into the calculation so everything else is the same so you end up with on Mercury with a string and you get the specific orbital period for Mercury um and then uh uh we can pass in uh so rather than repeat all this thing like what it was going to do what I've done is create a this I'm not uh this higher order function so we have function rather than turning a value a specific value like an integer this function actually returns another function and then that function will be used to process uh seconds so this function here takes relative orbit and basically adds into um into the calculation so this is this is like adding Mercury optimal period into that calculation and uh your then able to just uh have a more generic function that we can pass in each orbit into it but the the common part is done in this function and it's all the same and so we can do um and we have this uh extra function just to kind of take out some of the comment common things um I've got seconds to earth years uh uh given a second so I've actually just pulled that out and done some pre-calculation here uh of what the uh what the seconds are in terms of Earth years so again that's just factoring out a couple of bits that would otherwise be repeated over and over again and so it came up with this solution here which I think is on the website uh yeah so now we've got uh now instead of defining lots of common things uh the only thing we've got is this call to relative age um so we're passing in uh so we're passing in the orbital periods for each planet relative to uh the Earth's orbital thing so that's our original data set that we've got and then this um each of these uh will take relative age uh and inject it into as the relative orbit into this calculation and return the right result I can see we've got all the uh answers done um I did get a mental suggestion of using a macro but I think in we both agreed that that was like way over the top and macro is a really powerful way to extend the language um but they're slightly different they're slightly different um syntax and they're really most powerful for extending the language for solving this specific thing using a function or a higher order function is is much more appropriate I think uh in general uh macro is very powerful but then with great power comes great responsibility somebody said once um and it also like potentially adds a lot more maintenance to your code if you're adding macros all over the place and people need to learn them when they're onboarding as well so it can be very useful but they have to be treated with great respect as well and I've got about 10 minutes left I'm just going to squeeze in bank account uh this is quite nice um this is a fairly simple in terms of the like the algorithm it's quite simple once you know one key aspect of closure and if you don't know that then it's quite hard um so I have an iteration here so basically we want a bank account uh let's go look at the uh look at the instructions so we want an account uh it'll be accessed in multiple ways we can make deposits withdrawals um and the the interesting thing uh is that we can access the bank with multiple threads processes um so we need to manage some concurrency and if you watch the introduction video to um some of uh s Expressions then you would know that closure is very good at managing concurrency because it's got something called software transactional management or something like that is that all right software transactional memory okay closure STM something so ingrained I can't remember what it's called now yeah so if you can look for closure uh refs and transactions yeah you've got this software transactional memory there you go uh so there's a lot more details about that but essentially we can have something like uh something called an atom that will uh act as a a mutable container so everything enclosure is immutable so like once you define it it doesn't change it's a bit like a string in most languages once you define a string then you actually create a new string to be able to change that string enclosure everything is like that except for the software transactional memory aspects so we can define something called an an atom so our data structure here our state as it were we're going to Define as a bank account uh bank accounts and that's going to be represented by a hash map which itself is immutable so once we've created the hashmap we can't change it we have to create a copy an alter so we basically take the existing values in the hashmap we can change them or add to them or delete them and return a new hashmap and so we're not affecting the existing anything that's using the existing value values in the hashmap is not affected we're creating a copy of that so that way actually reasoning about all your closure code is very very simple because you're pretty much all of your code is deterministic and your values are immutable so you know exactly what's happening you don't have other parts of the system changing and and changing values underneath you without knowing things so should there be kind of issues and errors then it's very easy to narrow down what's actually going on as well but most of the time it kind of prevents you even making those uh issues as well so we use this atom function um to wrap is essentially we're wrapping the empty empty hash map we've got here into this container this container which we can change so it's it mutates we can we can change the value within it but the value within it is still immutable it still can't change we're just swapping values in and out which is why we need to use uh specific functions like swap there's also reset and we give them by convention a like a question an exclamation mark at the end of the name this is like a naming convention that we use that's quite common for functions so where where we kind of we are doing mutable actions we'll put a a bang an uh an exclamation mark after as the last part of the name so we're going to open an account and uh with this function and so we're creating a unique account ID so we'll be able to access that so if we have a look at the tests okay we'll look at the tests here um oh there we are tests the oil past e yeah you see so we're running bank account open bank account and then get balance um we're returning a zero so we only need to return um like the value but I'm using a I'm using a like an account ID just to make sure that the each account is unique if we're going to open multiple accounts we can return the account ID and we're associating uh the uh so we take the bank accounts map that's within the atom that's why we have to use a swap so we basically say we want to swap in into the atom and we're using a function to associate the key and the uh the value so basically going to create an account ID with a zero value so basically creating a new account with a random uid and zero as the value and uh and we're returning the account ID just so we know what that that actually is uh so that means when we want to close the account we can just pass the ID and again we could go talk to the atom and say we want to disassociate the account ID and then that just removes the key value pair and then we're done uh and then for get balance again we're using the account ID we're not using Swap this time we just want to look at the the value inside the atom we're not actually going to change it or affect it so we don't need a specific function to do that we could just use the get um but we do need to talk to the uh the hash map that's inside the atom rather than the atom itself so the atom itself is called bank accounts and bank accounts atom contains a hash map and if we dereference this come on uh oh open it so there we go um so if we dereference this uh this is using the this at sign which is the same as doing uh D ref Bank um and so that basically what that does it pulls out the the hash map from the bank accounts atom and from that hash map then we can just get the account ID and it Returns the value and then up update bank account is uh yeah we've got the account ID we've got some credit we want to apply to it and um and we're just doing an update function so previously we did associate disassociate and now we're updating uh so associate and disassociate just looks for the uh so associate just looks for the key and swaps in a new value update will take the existing value and we can run a function on that value to update it so here we've got the anonymous function and we're just going to take the value that we've pulled out of the existing account ID so that will be one if it was a new account that'll be sorry it'll be zero if it was new account and we're adding the credits that we've passed in as an argument to that and then so that function updates the value and then that value is put back into the uh into the atom and so then we can kind of do uh the multiple tests um there we go um so there is we yeah so you have now um bank accounts that are doing things uh uh one after the other so we need to make sure so the the atom makes sure that when all these different uh calls to the atom are made then only one call can be made at once and so it's kind of managing we don't need to lock the data before we change it the atom is doing all that for us and so software transactional memory it's a bit like when Java started doing uh like uh memory management for uh C it's it makes it a lot easier you don't need to do any memory management here and with closure using an atom you don't need to do any uh sort of locking and unlocking of uh this value this mutable container that we're changing that's all handled by closure itself alrighty I'm uh that's the end of the time I've got um hopefully you found this very useful I like to thank Bobby towers and everybody that kind of worked on the closure tracks it's very detailed very good uh things that everybody accesses them for making such a wonderful learning experience as well if you want to find out more about um some of the work I do for closure then you can go to practically.li and uh there's lots of videos there that help you in some books to kind of help you uh learn closure but also the the development workflow as well and some of the tooling that kind of helps do that as well so practically near them can show you how I've been doing some of the uh editor work I've done today uh this is quite new but uh I quite like it as well so thank you very much everybody and I will see you later thank you bye
Video description
Challenges - RNA Transcription (data structure, map) - Nucleotide count (frequencies, some) - Space Age (higher order functions) - Bank Account (Software Transactional Memory) Clojure CLI and Neovim editor with Conjure were used for a local REPL workflow - https://practical.li/neovim/configuration/astronvim/ - https://practical.li/clojure/clojure-cli/ This is the first live coding session in about 3 years, so it may be a little rough in places