Defmacro Clojure Tutorial - Code that writes code

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up guys in this video we're going to take a look at how we can define macros enclosure so let's get started [Music] cool so essentially a macro is a way that lets us write code that writes code and i'll show you why that would be useful so in this example i want to create a function that basically you pass it a function or expression it'll tell us how long that expression took to evaluate and then give us the result the api for it would look something like time taken and then we passed through [Music] an expression we'd evaluate this we print out this took however many seconds to evaluate or milliseconds to evaluate and return us to to start off i want to actually create a function that's just going to basically wait so i'm going to define a function here called weight return it's going to take in seconds and a result and then we'll spread sleep for however many seconds so we're going to times our seconds by 1000 and then we'll return the result evaluate this so now we can basically say weight return and pass it in two seconds and we'd wait two seconds for hey to be returned awesome so now let's look at how we can do this time taken function also i've never used this in videos before but we can actually just make a comment section or comment function and this takes in expressions and they don't get evaluated so we can evaluate comment we get null but then we can evaluate the expressions within comment and they work so let's get started i'm just going to clean this up let's get started creating this time taken function so i'm going to define a function here called time taken and i'm just going to actually move this below it and move this inside of here and with time taken what we want to do is we basically just want an expression we want to time how long that expression took to evaluate so we need a start time and i'm going to use system nano time for this so we can use some java interrupt and we can go get from system we can evaluate banana time from that and this will return us the nano time so let's use this to get the start time so i'm going to go let's start and that's going to equal that time and then we're going to evaluate the expression here and then afterwards we're going to need the end time so i'm just going to quickly grab this and use it to get the end time also and then we need to get the time difference so let's take time taking it oh time taken is the name of this function so turtle time and then we're going to take the end time minus the start time so star time and then i want to divide this by 100 000 because that will give us milliseconds and then let's wrap this in double and let's make this a double so now we need the result of the expression so let's create a new variable here called result and that will be the result of this expression and then here what we can do is we could say print line took total time to evaluate and then return the result so if we evaluate this we now have time taken but it's not going to work exactly how we think now let's evaluate this time taken function we get an issue here and that's because this expression has already already been evaluated by the time it hits here so this function is actually using the result of this evaluation so we're going to get 2 here and then 2 here and obviously this can't be run as a function so what we can do here is pass through an anonymous function and if we evaluate this now cool we see it's a 0.1 milliseconds to evaluate and we got two so that's cool but that's not the original api i wanted i wanted to pass through a function like this using macros will allow us to do that so let's convert this time taken into a macro but before we do that i want to show you syntax quoting so you may be familiar that we can use quotes to get a symbol so we can make like a function here list one two three and if we use well if we don't have the quote then we'll get a list returned with one two and three inside of it but if we quote this then we get the actual symbol value which is basically the code but you might not know about backspace quoting so if we used a backspace here and evaluated this we get the the namespace where list comes from and then one two and three but what we could do now is we could define a variable here let's call it bar one one evaluate this and now instead of using one here we could use this tilde symbol and write var1 and evaluate this and now we see that this variable that we passed through has been replaced with what it actually is so that's going to come in handy pretty soon so i'm just going to get rid of this well actually i want to keep it let's keep that in this comment so let's get started actually creating a macro so it's going to be very similar to the function that we wrote so in actual fact i'm going to just copy this whole thing and comment this top one out and let's just copy paste it here and the first thing i want to do is not define a function but define a macro and to do that we use def macro this takes in the name of our macro which time taken is cool the arguments that we're going to pass through our expression is cool so now the first thing we want to do after we've defined it as a macro is return a backspace quoted list and now we don't need this anymore these brackets around here anymore because this expression won't be evaluated here it'll be evaluated inside of the actual function here we can replace it with tilde and now it will execute the function that we pass through so now we actually are going to pass through something that will look like this copy this and it will be it'll work like that let's see what happens now so if we evaluate this run time taken so now we see another issue it's trying to get these symbols from our local names from this current namespace but they don't belong in this name space they belong in this lip binding so to get around that let's just clear this we just use the pound sign so we can put the pound sign here and this will let the macro know that these symbols are evaluated within this macro so let's add more of these and if we evaluate this now and then run this that's perfect we can actually also improve this print line a little bit we can show the expression that was evaluated so we can take this and if we quote the expanded expression evaluate this and then execute this we can see what expression took how long to evaluate which is really cool awesome so now we nearly finished with our time taken macro but what i actually wanted to do is i want it to allow us to pass through multiple forms one plus one as well as this weight return but right now it can't it can only take a single expression so let's update this a bit to use multiple expressions so the first thing we need to do is make this macro take in multiple arguments and we do that the same way we do with functions by using and expression and then what we need to do is evaluate all these expressions so we can use the do function so do basically takes in like a function body with multiple expressions so plus 1 1 it will evaluate that to 2 and then we can do plus 1 2 and that will return 3 but it will evaluate all these expressions within its body so let's use that here but do and then evaluate our expressions here and then if we evaluate this let's see what happens so we can see that this time taken is no longer giving us an error because we can take in multiple arguments i'm just going to clear this up here and let's evaluate this and now we're getting an error so to see what this error is i'm going to use the macro expand 1 function and that will expand this macro out and show us what code is being generated from time taken so let's just copy this and i'm going to wrap this with macro expand one and then i'm going to pass through the symbol by using the quote and let's evaluate this just clear it up and now we can see that our macros expanded and we can see kind of what it's doing and here we can see what result is being bound to and it's being bound to this so let's copy this out here and just see what that looks like in a more nicely formatted way okay so what it's doing is this is being passed through as a list and that's because when you pass through multiple arguments into a function they become a list but we don't want it to look like a list we want it to look like this so to do that all we need to do is add an f symbol here and now if we evaluate this and we evaluate this and we look at our do function here we can copy it out put it in here and we can see that it now looks how we want it to look awesome so this should work now so let's get rid of this clear this up evaluate this and evaluate this cool and we can see that um these expressions took this long to evaluate and returned hey return here and that's essentially how to use deaf macro i hope you guys enjoyed this video if you have any ideas for videos that you want please put a comment in the description and i'll get to them as soon as possible i promise i'm getting to everything um it just takes a while if you're new please like and subscribe on this video it does help me personally feel better about myself cheers
Info
Channel: on the code again
Views: 240
Rating: 5 out of 5
Keywords: clojure, clojurescript, defmacro, macros, tutorial, lisp, rich hickey, macroexpand, macroexpand-1
Id: GBdkaFpO_1s
Channel Id: undefined
Length: 10min 12sec (612 seconds)
Published: Mon Oct 18 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.