Pattern Matching in Clojure: Best Practices

0 0

my name is Shawn Johnson I work for path I'm a software engineer I run the remote engineering team at path how many folks here are remote engineers where's the hints nice go remote engineering that's about half that was impressive so today I'm going to talk to you guys about pattern matching enclosure and so how's this going to go I'd like to talk for a few minutes maybe 5-10 minutes about history of pattern matching within programming languages and how we find ourselves here today in 2015 wanting pattern matching with enclosure and then we're gonna go through some how to's about how it actually how to work how it works how to use it and then I'm going to share some we world experiences that I've had using pattern matching for last few years enclosure and the presentation is going to be very code heavy so that's good we're not just gonna talk concepts but we're gonna share a lot of code it's not gonna be live coding I've seen a lot of live coding here at close your west and I'm not that brave and I'm just not that guy so rest assured though this will be mostly real-world examples pulls out of my own code and projects some open source and as well as some closed source code and we'll have a few examples where we need them for clarity but you know I'll try to keep those in a moment brief so a little bit about the history of of pattern matching so we've got a rich history within programming languages and it starts all the way back in the 60s with with snowball and that had a form of pattern matching around strings and something we all in this room would recognize that it started to look a little bit like regular expressions and then in lakes in 72 we got prologue and prologue is a language that has uniform and unification is a kind of extra-special spooky form of pattern matching and those guys in surveys who knows what they were doing but there was a lot of functional and pattern matching program language work being done in the 70s and 80s based on a lot of it was happening in Prolog and we found ourselves in the late 80s with a language Erlang which was straight out of the prologue tradition but crossed over into commercial use in telecoms initially and later as a highly concurrent language used on the internet so there's a rich pattern-matching story that spins back from the 60s to today and it went on in the 90s and especially in academic languages we saw more attempts at pattern matching but where do we stand with closure you notice there's not a lisp thread and through my my historical tour there but let's let's reset back to those crazy 70s and look at pattern matching and prologue and again that's the kind of pattern matching called unification and what we do in unification is we just define facts or rules in this case we've got two prologue facts that define what makes a line vertical or what makes it horizontal and the key thing to look at in these two definitions is it's just the only thing that changes is X being the same in a vertical line and Y being the same in a horizontal line you see in the vertical line we have X we have Y and Z for the y axis and the horizontal line we have x and z for the x axis so that's that's starts to show how unification works and we can ask Prolog is this point vertical and is this line vertical and the line with the points 1 1 and 1 4 is in fact vertical and it could tell us when a line is in vertical we haven't this is our entire program we haven't done anything imperative we've just declared what's true about the world what's logically true and Prolog is using unification to seek out truth within our our data and paired it back to us so that was a simple example and it gets a little more complicated here we want to having a function that every three takes two lists depends them together seems pretty simple we do it cursive Lee with the first rule saying if we have an empty list and a list and pending them together it's just the list that isn't empty that makes sense and then we get our first rule here because it has the two parts it's a rule and it's a it's a recursive rule it's it's recursing back on a pen and it's working its way back towards the empty list and then it's gonna as the recursion unrolls it's going to accumulate the the answer back in l3 and so you don't have to exactly understand how the unification is working there the point is Prolog does and you can ask a questions and it will tell you that ABC pending at the de is ABCDE no surprise there but what is a little surprising is how this is actually happening Prolog is keeping l3 unban unbound variable as long as possible and the actual the book that I pulled this example out of doesn't even know how to talk about unification it says the answer crystallizes out like a snowflake forming around a grain of dust that's awesome that is awesome poetic and not how we all want to program I think so it does spooky things right we take that same append implementation and we we give it the answer and it gives us back the question like it starts playing jeopardy with us right it tells us what l2 is when we miss that out so we get this stripping apart behavior when what we were trying to do is write the behavior to append the two things together it gets even spookier than that we could start to ask you questions about sort of hypothetical universes what could L 1 and L 2 be and it tells us well one could be empty and L 2 could be the whole string and then this semicolon says will give us more and it's gonna backtrack unbind some of those variables and tell us well one could be a and then L 2 would have to be B C D and E right so this is how this two-way pattern matching works in in Prolog so it's it's it's two-way we can have found things go done bound and unbound good abound and what makes it quite different than the rest of the parametric we're going to be talking about today is we can have unbound matched to unbound and we just keep track of the fact that these two things are going to be the same value eventually and then Prolog will defer when it actually finds the value there so if any of this is interesting to you there's closure if equates to explore unification with core logic and or you could dive right in to learn Prolog the example we post came out of learn Prolog now a online resource but that's not exactly the type of pattern matching that I want to focus today on when we look at the best practices it's it's really the the one way pattern matching where we're we're gonna take something that's bound and match it to something that's unbound we're gonna take something that's unbound and match it to something that's bound a little less spooky lieu easier to get her head around and where I came across this kind of pattern matching and incorporated it mostly into my workflow was was with Erlang that was the first functional language that I used and her laying was first implemented within Prolog that was the language that was implement and then it bootstrapped off of Erlang once her Lane was written uh and they still has the syntax of Prolog it looks a lot like like Prolog and although there's alternate syntax now including Lisp flavored Erlang which is kind of interesting for for us folks but what they what they did is they took Prolog a language that is not known to be concurrent didn't have concurrency for a long time certainly isn't performant enough to be considered soft real-time or known for being having very deterministic performance or great uptime and they said our goal is to create a language that has all these characteristics the only way they were able to do that was the skin and avian developers these telecom developers who created her like they pulled unification and backtracking out so they didn't implement that in their language what they were left with is something that it's quite dear and near near and dear to our hearts which is single assignment and immune ability that's pretty awesome but also this rich one way of pattern matching story which is what was left over once they pulled unification out of Prolog so what does that look like in Erlang well here's some pseudocode that's vaguely ruby ish python ish i made it up and simple function definition and we've got a regular old conditional where we're gonna go down to a few different paths and choose a B or C everyone in this room can understand this the pseudo-code well Erlang has much more declarative and concise and I think appealing implementation of the same code we actually take the conditional min and bake it in as part of the function definition itself so if we want expression for if our argument is 0 we get expression a if argument is less than 0 we get expression B anything else we get a expression C so you guys can follow it's the same exact code as the pseudocode was just more declarative more concise simpler similarly if we need to if we need to have our condition be based on types we can do that using guard expressions within Erlang and tests on the the types of the arguments but but pattern matching in Erlang is not just for function definitions although it's used extensively there but use throughout the language it's very pervasive so I got very used to having pattern matching it's just part of how I thought about functional development here's an example of a case within Erlang which is we're just a regular conditional but this conditional works based off pattern matching so we're gonna pick the type of temperature scale that we're using within the what's called an early tuple these those curly braces and we're going to use also combine that with our guard expression in some cases and and get the right output from this this case expression so if you're just in any of this you can you can learn about Erlang and I think it's it's it's fascinating to see a language that has pattern matching so ingrained in it but what about us that mean we've talked about Prolog we've talked about Erlang but but what what do we get enclosure for for pattern matching and I'm going to give you a little hint we have something as a lisp called macros and so that's that's that's pretty awesome even more awesome more awesome earth is we have superheroes within our community that know how to wield those macros for us now we're talking right that's my kind of solution but first we can get started without any super powers required just right in the cloture language itself we're already doing some pattern matching every day whether we realize it or not so let's take a look at some of that the first thing is to get our pattern matching thinking caps in place is to think about be structuring which we all do as a mini pattern extraction language so here's an example we just have a sequence of person names and we do some regular destruction this is closure code that we would all run across in in our day to day use of closure and what we've really done is we've we've said our data has a certain pattern where we want to extract the first thing out of it we want to strike the second thing out of it we want the rest of it we want the whole sequence as a as a fourth thing so it's regular destructuring but we're we're starting to describe the pattern of our data structures and pull elements out and so think about that as as pattern extraction a slightly more realistic example would be a map used to hold configuration information may be pulled out of edn or something here's the configuration information for a database and we would use pattern matching pattern extraction to pull the pieces out so we could use them to connect to the database nothing too unusual there and and that destructuring is it's quite powerful we've got all sorts of things that help deal with sequential data and associative data structures to give them default values and you guys know how des structure works I think but but maybe you're not thinking about this is a mini pattern extraction language and you ought to start thinking about that way because the macros that we're going to explore are all built up out of these same concepts and primitives but beyond destructuring if you're using multi methods at all within your closure code then you're using a very very simple pattern matching macro so multi methods are made up of of two macros one of them is def multi where you define the method and the multi-method enclosure for those of you don't know it's just a its closure zone kind of functional brand of runtime polymorphism so you define essentially a functional interface then you have multiple implementations of that and that runtime you're going to select the right one based on based on dispatching value a value of your data that's going to point you to the right function implementation so that's how multi methods work and the the highlighted part there is the is where I'm defining within the multi method what the dispatching value is going to be in this case the value of the exchange key and so when I call that at the bottom there you see order less being invoked with exchange is cripsy that's going to get pattern match to the implementation above where you step the DEF method macro with cripsy as the has the dispatch value that make sense so that's it's very simple it's just a simple value and it stays pretty simple but it's it's a form of pattern matching to get some runtime function dispatching another example of a macro built right built into our language that starts to give us some pattern matching capabilities this case the simple case macro we've all used the simple case macro here's an example if the count is zero we're gonna get one string if it's one we're going to another it's two or three or many you guys know how how case works you could see the example invocations there and that's kind of a toy example here's an example used an anchor point pulled out of my real code where I'm getting back an error then I want to return from the the web server and depending on what what exactly happened why the request wasn't processed I'm going to return a different kind of response and so I'm just pattern matching on reason which is the variable holding my bad thing that happened and I've got different keywords for each of the different cases right so it's very very simple pattern matching but the problem here with case as a pattern matcher macros is sometimes it's too simple this quote is pulled from the doc the docs for case and you can see that the test constants they're not evaluated right they must be good pal time learner roles and but you don't need to quote them but they're just a nert they're just data right you can't have an expression user defined function so what if your for your case statement you want to say does it contain a certain key or is it is there an inequality is it is it greater than a certain value or something more complicated you can't do that with with case and there's some other macros that help us with conditionals like Khan and convey that gets a little closer to more complicated pattern matching where we can start to define some expressions and use them but it's they're still pretty limited in the same way that the case is limited so we haven't really been overusing macros even though we're using some some almost proto pattern matching we're not really tapping into our superpowers that our superheroes have created for us so so we need some more macros because macros let us create the language that we want not the language that that we have and the language I want feels looks and feels and behaves a little bit more like they're laying that I first started functional programming with so I need to tap into those superheroes and the first one is gentleman you guys might know he's Captain America and it's David Nolan and and the other super here I'm going to tap into first is is Ambrose and he can't be Captain America because he's not American but he he could be spider-man and so these two guys going to help me get the language I want out of closure and so these two guys back in 2011 I think created a core match and core match is a much more powerful pattern matching macro and this is pulled out of their their lips out of their readme it's an optimized pattern matching library for closure so David's giving hold talks on core match where he's dived into the details of how the sausage is made and why it's so optimized why it's as efficient as it is that's not this talk we're gonna talk more about how to use it the first thing you have to be able to use it is just pull in the dependency in the line or if using booth is it's like different way to do that and then pull it into your namespace you just need to grab the one thing the match macro and you're ready to go so what does it look like here's a toy example one of the last of the toys and just so you can get the feel of it we were matching on an input it's clear here we think the inputs probably a associative structure or map of some kind and we're saying if there's a key in this associative Dave structure and the value of if there's a key that's the key word key and its value as foo then we want a certain expression if there's a key and its values anything so that that underbar which comes from the Prolog lineage it means match on anything but don't bind on that I'm not gonna use the value but go ahead and match on it then we get another expression and we can use this else keyword to say otherwise express the third expression so there's core match it starts to at this point looks a little bit like case syntax wise end literals match just like the case macro does if we have a var it's always going to match it's going to be bounced we can use it in the subsequent expression that we select if everything matches and the underbar that I mentioned it's always going to match and in pneumatically if you use an underbar you're signaling that you don't care about the binding so you shouldn't use a variable if you're not gonna actually use the variable it's just you're talking to that a programmer saying we're not going to use this in the expression we're supposed to get a lot more powerful though than case is we can have this keyword guard and guard is going to be a named function of era t1 it could be a name function or an anonymous function of era t1 that's going to return true the--or false e and if it returns true the-- that section of the pattern is going to match never returns false that's of course not going to match so we can start to get pretty complicated pattern this the set of functionality so here's some examples pulled out of real code here's an example not using any guard expressions but that does use quite a few of the LR elements so first thing we do is we use the macro match and we match on nothing for the first argument and empty for the from the next to an empty sequence and an empty map and if so we're going to get a certain expression if the another match another pattern that we're gonna match on is if the third thing is nil if the third thing has a certain key etc I think you get the idea and that in this case we we didn't care to bind and capture any of those values if we needed say this log and what the value of the category key was we could capture those with variables and then use them in the expression that we selected so that's that's kind of how poor match works and it has else as we saw in the prior example but here's another use of it in pulled out of row code and you start to see where we were pulling in these guard expressions and the guard especially is working on the argument to the left of it so knock guard is guarding that argument that anonymous argument guarding of absolute ri so this case we just have one argument and all the guards are acting on that but if we had multiple arguments we could put the guard after the argument that we were trying to have the expression evaluate so this is great but what if no pattern matches that's certainly possible in all those examples that we showed where we didn't have an else it's possible that we just wouldn't have a match at all and in Erling where we're this thinking maybe originates from the idea is that you want to let things crash let it crash it's a mantra in the Erlang community we don't quite have that mantra within closure but we do want an exception happen that's the equivalent of let it crash that's something unexpected happened the data doesn't look like we thought it would look like we don't want to cloud our code with lots of corner cases and and edge conditions that we we don't expect to ever happen no so we just let the macro for the illegal argument exception and it includes some interesting data about what the pattern that couldn't be matched was to help us in debugging so in this way pattern matching helps us start to assert about what our data looks like everywhere we might put an assertion about the shape of the data we're using pattern matching we've essentially got a built in assertion if we just match on the patterns that we expect to see that are we will see if our code is operating properly we don't match on the patterns that indicate some unexpected or improper behavior then essentially we're acting as an assert so we deal with those possible patterns we clear nor the rest keep the code very clean and declarative and just to make that concrete I show in the top example we have a we're matching on a map and we do expect that the key might not be in there so we're gonna include an ALICE because that's expected one of the outcomes that we would you expect to have happen we don't expect that to have happened it's better not to include the else in our pattern matching it's not a best practice to always put in else in there for example you want to have it fail with the condition of why it failed why the data is invalid misformed so with pattern with this court match macro do we get closure script support and the answer is yes we do we we can pull it in slightly different syntax to pull into macro but core match works within closure script which is great so if everything we want in need I think kind of head of core match we can select cases based on patterns we can do declarative pattern matching placing conditionals in some cases but one of the things we saw with Erlang was function dispatching based on patterns and we haven't quite seen that yet so do we have one more you know superpower within our group of Heroes here and we do and that's that's this Iron Man guy here and when we pull his Iron Man mask off we don't find we find he's got a sec secret identity I don't know who Dennis is actually I have his avatar he's a wizard so he he's a wizard underneath and and I don't know how to pronounce his real name if anyone does they can shout it out but I'm not gonna attempt it now he goes by Dennis though so Dennis created a macro in a library called the fun and as is befitting someone who has two secret identities it's it's it's macros all the way down and so the fun is a macro that is wrapping the core match macro okay so it's it's a library that's a macro wrapping into the library that's a macro awesome and I didn't have to write it and so what does this look like so the fun is a parametric macro for example we were missing for defining functions with patterns so we pull it in just like we would any other library in in London for example and pull it into our namespace and in Dennis his own words we get a macro to define closure functions which with pattern matching just as Erlanger elixir awesome that's that's what I wanted and when we go to to use that you could say well we have argument Garrity overloading right we can regular define a function called say hi and say if we have one argument do one thing we have two arguments do another thing well that's our kind of row syntax our syntactic model that we use for the fun so the fun has the same kind of thing where we could say if you've got one argument if you've got two arguments we can start to inject patterns in there and these are the same patterns we saw in court match so we have literals like strings like Dennis you can have keywords like caddy we can have variables that get bound like name and the third pattern we can have the the underbar to say we don't care about what the value is match on it but we don't need it bound and so it's syntactically looks just like argument arity overloading and syntactically it looks just like core match not surprisingly everything we just learned applies because it's a wrapper around core match now so everything we just looked at is how we write these patterns it's not a new pattern language so let's look at a more realistic example let's say we have two points Latin and launch and we want to know if if they're valid or not we can have we could just write two patterns one pattern for if they're valid one pattern if they're not if these gar conditions hold around the lap and around the lawn then it's valid otherwise it's false and you notice one curious thing maybe why did I keep the the tuple of two underbars for for false think about it from it the reason is goes back to failing if the data doesn't look like we expect all right we expect someone to call valid geopoint with a Latin along if they called it with something else say just a lat then it's not just that it's not a valid geo point it's not a geo point at all right so the data is just not what we expected so we're gonna fail with the with an exception rather than just false and that's just how I chose to write this particular function to meet the requirements so what does it look like in anger I apologize the font size went low but I didn't mean for you to grok all the details here other than to appreciate that this looks just like those core match examples that we were studying in more detail it's just in this case we're actually defining our function in terms of of patterns rather than a conditional in terms of patterns but everything else looks just the same or we're matching on the same kind of literals in the same kind of guard expressions as before so we've got our two pair of macros we've got pattern matching everywhere we need it do we get this in closure script unfortunately don't we get a github issue instead so let's get this fixed I give this talk once before and I promised the audience that I would fix this and I immediately forgot I hadn't even left the building and I forgot but I remembered when I brought these slides back up so I'm going to promise you guys to get this fixed and I'll try not to forget so how well does all this pattern matching work in practice I want to talk switch years a little bit and talk about some of my experiences and some best practices now that you understand how how it works so I've done lots of Erlang and lots of elixir where pattern matching was would use pretty extensively then within the closure world I first started used it incidentally I'd I added these macros to my toolkit and when something really jumped out at me as needing pattern matching to be clear and concise and declarative and to get rid of some conditionals I would use it and so I had a couple projects where I kind of incidentally used pattern matching one of them was open sewer she could take a look at that I then did a project later on where I said what if I deliberately used pattern matching what if I used it everywhere that I could how am i my code turn out you know if I deliberately thought you know should I be using pattern matching here as an actual coding practice one of the kind of checklist things you go through mentally and in the project that came out of that posterior you guys could could take a look at and I think it I think it's a great code base I it's not necessarily super idiomatic closure because it uses pattern matching rather extensively but I think it should be more DMACC than it is I think closure code should look a little bit more like that and I think it's it's nice and clean and simple and declarative and and I'm quite happy with how that turned out so inspired by that and barked on to other projects so I said well what if I use pattern matching maximally what if I didn't do any other kind of traditional accept pattern matching and so I've got these two projects are both in progress and the verdicts still out I'm not quite as bullish about maximal use of of pattern matching I think I think it's got diminishing returns if you if you go completely crazy with it so I think the sweet spot is to use it deliberately to consciously think about when you can use pattern matching to make your code more declarative or code simpler remove some conditionals and I think that's that's a nice sweet spot for it and does it hurt anywhere that's that's a question I sometimes get is you know where shouldn't I use it in it for the most part it's it's a it's it's nice does have one problem that I've run into quite a bit in a barrel usage which is the guard expressions are a bit myopic what I mean by that is here's a toy example but I've got two arguments and I've left off whether this is or the fun because it applies equally to both but I want to guard on I want to find out if the intersection between these two arguments is empty and if the intersection is not emptied then I want this pattern to match seems reasonable right it's like a pattern we'd like to right we can't quite write it like this because you see that question mark dude that's not syntax that's me scratching my head there's nothing I can put there to refer to the other argument right I can guard on McCoy's or I can guard on Hatfields and I have an expression there but I can't guard on both and consider them both within the expression that's just a limitation of those macros as they exist today there's a workaround which is that you could pack those arguments up into a tuple so you just take half those in McCoy's pack them up into a sequence and you have one argument called participants that you can then guard on write your expression as you as you'd want to to look for a non empty intersection so that's just something that I find occasion I have doing my code not too often won't have ten times or so this will come up and you know makes the pattern match encode not as as simple as I would like it to be so what are some best practices for that I found for applying this and one of the things you can do is use pattern matching to eliminate any conditionals that are the first expression of a function and you can also use it to eliminate nesting additionals and I'm going to show you one example that hits on both of these at the same time it's a twofer so this is some closure that we can all grok I mean it's not the most complicated thing in the world it's not immediately apparent either you have to think about it for a second to figure out what is that was happening and the fact that there's kind of three cases here in this a conditional with an embedded conditional but if we wrote that with the fun and pattern matching I think that closure code is a lot more clear it's immediately visually clear that I've got three cases and what I'm doing in each of those three cases so I just think that second set of code reads much nicer and is what I would hope would become more you matic closure over time another best practice for pattern matching is when you've got varied function inputs coming into the same function so in this case we've got the third argument is kind of the key argument here it could be nil we've got to do one thing it could be a scalar we have to do some other set of expressions it could be sequential it could be associative so rather than writing conditionally a function that has complexity to handle this we just define like we would inner language define the function four different ways based on the pattern matching what our incoming arguments are this kind of varied function inputs works really well with pattern matching in this last best practice is my absolute favorite one I call it the recursive function pattern of pattern matching and comes straight out of Erlang where when you have recursion in Erlang it's usually made up of three or more function definitions all together and so you have a set of function one or sometimes more than one set of function definitions that are pattern matching to your start cases or your start case then you have one or more functions that are doing the work of the recursion that are progressing towards some end cases and some in cases we eventually need you need to stop recursing and return a result and so that pattern of start work and end is is just how recursion kind of is defined within Erlang and so what that ends up looking like I've got the color code in there we've got one pattern that's our start case it happens to be era T to going to era t3 and that's a very common in recursion you've you've got to initiate and and have your accumulator you're going to accumulate the result you might have a couple arguments or a few arguments coming in and you've got to have one or more arguments to accumulate your results as your as your recursing and you better have some end cases or at least one in case that you're working towards for your persians never going to finish and these second two patterns match in cases and in having two of them is not so uncommon one of them is a short circuit pattern it's the same like there actually isn't any work to do here we didn't ever need to recurse and one of them is the normal end case of the normal recursion and then you better have one or more patterns that are actually doing the work of recursing and getting you towards the end state and and that's what's happening there Zeus or eating a list and cute landing results so that's very typical pattern matching in Erlang and this is typical or excuse me typical pattern matching based recursion in Erlang and this is what typical recursion in closure looks like this is the definition of zip map straight out of the closure source code and it's okay I mean this is zero matica I like it like I can read it and understand it and it's pretty good and if we look at who wrote it I mean that guy's not a complete bozo knows what he's doing right I'm not gonna say anything wrong with this code but everywhere that we have recursion we really do have this pattern this hidden pattern of start work and end and if we make it explicit I think I think recursion starts to make a little bit more sense for everyone so where is it here we do still have a start case and that's what the loop within the function we have we come in with two things keys and values and we need a third thing we need to accumulate into the map that's going to be our end result so we have this starting pattern that the start of our loop and we're gonna we have a conditional to say are we done yet if we're not done we're gonna work towards the done state and we're done when we turn the map right so we still have this same pattern of start working end but this is how recursion typically looks within closure and it's okay but I think it could be better and here's my implementation of it with the fun and pattern matching and I think this is just simpler more declarative clearer and it's I like looking at this code better it makes more sense to me so where's our pattern there we've got four patterns for cases we've got our start case which coming in as era t2 recursing with era t3 with our initialized map we've got our to end cases notice we have two here instead of one before we were kind of hiding the fact that there are actually two ways for this to end we could end with running out of keys or we could end running out of values and I think with this Restatement that fact is much more clear to the reader and then we've got our case where we're going to work towards the end by working through the the keys and the values so we can compare those two and I think I think you guys hopefully agree that the one the bottom is at least is clear and which you've looked at a few times maybe you will agree with me that it's it's more clear than the example on the top so that's the recursive function pattern matching pattern for lack of a better word so let's just restate some of those takeaways patterns that were suggesting use they're not new they're not scary they've got a rich history with in programming language design they can lead to simpler and much more declarative code please do use core match into fun we've been given these superpowers I hope we all start using them and there are some best practices you can take away from this as you start to use these libraries in these macros you can use pattern matching to eliminate those conditionals especially when they're the first expression of a function or when they're nested and great for using to dealing with varied function inputs and then my favorite is that Restatement of recursion as the start work end pattern I think that's particularly strong so I'd like to thank a few people for having me here today cognitive put discomforts on and the creators of the libraries and things that we looked at today and I'd like to open up for any questions yeah so you should always take a look right when using macros do a macro expand and take a look in the codes relatively simple relatively straightforward so what I would do is I would encourage you they answer this question sorry I'll restate the question the question was what is the performance implication of doing pattern matching and I'd encourage you to take a look at David Nolan's talk he did back in poly 2011 or 2012 to the New York City closure group it's online it's it's about an hour long and he walks through kind of how the sausage is made and how he builds up kind of truth tables and reorder some of those arguments to get really efficient implementation of pattern matching within court match so it's very efficient it it's slower though you're trading off developer clarity right for runtime performance those macros are not going to perform as well as as Rich's original recursion implementation and I wouldn't I'm not trying to suggest that rich should have written his code like like like I wrote it but we're not writing typically things like zip map that are being used by everyone right and can stand to have that kind of performance tweaking to them where you have extremely heavily used code that you know you need to study and make porn south musicians to you're probably gonna eventually over time I eliminate some of this pattern matching that you might start with but you know you don't want to suffer premature optimization majority of the time our code doesn't ever need to get looked at from a ports perspective right we're dealing with relatively small data structures relatively infrequent usage and developer clarity speed of writing the code speed of people understanding the code is really the bottleneck not the performance at runtime but often times up as you start to study isolate before it's bottlenecks and eliminate them you might eliminate pattern matching in the process other questions down here yeah those haven't really converged at this point the quartet came much later and not not too much has happened I think to pull those two things together I think it's I think it's an interesting area and the fact that you know Ambrose was involved in both could lead those things to come back together in a really powerful I'd love to see you know a reimagining of core match in light of what's happening in core.typed but I you know I think or typed is still a moving target maybe over there they don't write if you use record record in the macro you're still ending up with recur in your code so that doesn't change and so you're still getting either an error because you're not actually Terry cursing or you're getting the performance of tail recursion so it doesn't doesn't necessarily change the game because if you write your recursion in the kind of pattern I described they're using recur explicitly and they're getting another tail recur type of behavior but that's a great point that Erlang as a language sort of embraces recursion and tail recursion in a way that with its VM that was created just for hurling in a way that we can't with her VM that was actually created for Java that would that we have other questions let's see yep up there okay repeat the question and I'll summarize because there's a long question basically asking about just dispatching up the the type of the of the of the pattern and that being a very natural way to do pattern matching if you've ever had a language to experience that so interest is sort of in the sense that guard expressions anything truth of your falsey will work so you absolutely can introspect on type and do things like that too in your guards present so guards can get very complex they can call your easy to find functions that you know gonna have their own namespaces and you know you could there's no limit that there's not a like the side effects are limited of what could be a guard expression with these macros that they're not or you could go off and call a database in a web service you could go crazy thing right in these guard expressions and unless crazy things like introspecting on types and and figuring out but syntactically it's not maybe as clean as i think you're you're hoping for what you end up writing those expressions so it's i still think there could be some benefit of bringing core type together with with core match and the fun other maybe back there it's it's still sequential right yeah I don't know I'll repeat the question try to summarize it again it was just a challenge to how ultimately how declared of this style of pattern matching is because it's still order still matters here and there's there's still a sequence the patterns are going to be evaluated and one after the other and something that's truly declarative you think about being able to throw like in a prologue sense throwing a bunch of facts against the wall and just whatever is true is couldn't happen whenever you know pulses are gonna happen right and in the sense that order isn't and something that's purely declarative order does it matter right even just saying that there's an order is it putting some imperative structuring into it so it's true that that that observation is absolutely true it's not it's not as declared oh but I think it's it's a step in that direction the question final part of the question was there have any ideas about how we could get closer and I don't not at the moment I haven't seen anything that that gets us closer I think I think it's possible with with macros to to get a lot closer and to have something that's more declarative and less sequential I think the reason these macros are written in the way they are is is the question that we had first which is for performance I think is I think to make them more declarative would make them less performant as well maybe one more question because I think we're at a time in the back yeah it's it's question was can you match moment statement answers no both of these macros are just matching the first one they that matches in and the order does matter it's it's in the order that you you make the patterns so that's it we're out of time if folks have questions they can hang around afterwards