What do you want to learn? Leverged jhuang@tampa.cgsinc.com Skip to main content Pluralsight uses cookies.Learn more about your privacy Functional JavaScript Libraries Playbook by David Mann This course is about exploring some popular functional JavaScript libraries and seeing what they’re all about. We’re heavy on demo and light on slides. If you aren’t familiar with functional tenets, we cover them right at the beginning. Start CourseBookmarkAdd to Channel Table of contents Description Transcript Exercise files Discussion Learning Check Recommended Course Overview Course Overview (Music playing) Greetings and salutations! My name is David Mann and welcome to my course, Functional JavaScript Libraries Playbook. I'm a cofounder of a small startup and have been doing JavaScript development for, let's just say more years than I'd like to admit, but I do remember where jQuery was the new shiny object in the JavaScript world. Over the last few years, functional JavaScript development has taken on that shiny object status. If you haven't specifically done functional development, I bet you've been impacted by it, and have probably even written some functional code, even if you didn't know it. This course is all about exploring some of the popular functional JavaScript libraries and seeing what they're all about. We're heavy on demo and as light on slides as I could get away with. If you aren't familiar with functional tenets like pure functions, currying, and composition, we'll cover them enough to get you up to speed right from the beginning. We cover six functional JavaScript libraries in the course. In no particular order, they are ImmutableJS from Facebook, not strictly a functional library, but an important player, nonetheless. Also, Ramda, Sanctuary, Folktale, Monet, and FKit. These are all open source, community-driven libraries that make functional programming in JavaScript a lot easier. By the time we're done, you'll have been exposed to all of these libraries and gotten a good look at how they work and what they provide. You'll also be all set to start including whichever of these libraries strikes your fancy right inside your react, view, or Angular projects, or really any JavaScript code you're writing with any framework, other libraries, or just plain vanilla JavaScript. Before beginning the course, you should be familiar with JavaScript development, but you don't need to have any functional programming experience, as the course includes what is likely the world's fastest functional programming overview right up front, with code and pretty pictures and everything you need to get started. I hope you'll join me on this journey to learn more about functional programming in JavaScript in the libraries that can make it much easier with the Functional JavaScript Libraries Playbook course at Pluralsight. Functional JavaScript 101 Getting Started Hi, and welcome. In this course, we're going to be taking a look at some of the most popular JavaScript libraries for functional programming. Specifically we're going to be looking at these libraries, Immutable.js, Ramda, Folktale, FKit, Sanctuary, and Monet. Now before you ask, yes, there are many other functional libraries out there. There's no way I could cover them all. Generally I picked the libraries that are getting the most attention right now, that are recommended in forums and are still actively being maintained. I also gave preference to libraries that gave some type of nod to the fantasy land specification. If you're not familiar with fantasy land, we're going to be talking about it shortly. Before moving on, though, I feel that I need to at least mention two libraries not included in this course, and explain why. Those two are Underscore an LoDash. These are incredibly popular libraries that have a functional aspect to them. They weren't excluded not for any negative against them; rather, they were excluded for two primary reasons. They're not strictly for functional programming, there's a lot more to them, and also because there's a ton of material already available for them. My thought is that they're probably not libraries you'd pick up if your only goal was to implement functional programming or learn functional programming, so I left them out. Let's take a look at specifically what we are covering in the course. We're going to start with a very quick, and I do mean very quick functional programming 101. The important bits of functional programming in about 15 minutes; certainly not enough to make you an expert, but enough so that you'll have some basis to stand on when we look at the individual libraries later in the course. Next we're going to have a discussion about choosing a library. I put this near the beginning of the course, because if you're short on time, I want you to be able to see the strengths and weaknesses of each library early on, and then just jump to the module for the library or libraries you want to investigate further. The next set of topics we'll cover is the individual libraries themselves. In each module I cover a quick overview of the library, and then jump into looking at its major features. These modules are largely demos of the libraries in action. Last, we take a look at the question of, but I'm using React, or Angular, or View? Why do I care about these libraries? In each case, I cover how and where to integrate functional libraries into the big three of JavaScript frameworks. Specifically in this first module here's what we're going to cover. We're wrapping up the Get Started material with this slide, so next we begin the functional JavaScript 101. We'll cover each of the topics you see here, pure functions, composition, currying, et cetera. We'll end this introductory module with an overview of the fantasy land specification and why we care about it. So let's jump into our functional programming 101. Functional JavaScript - The Important Parts We're going to start with quite possibly the world's fastest overview of functional JavaScript here. This is by no means an exhaustive review of the topic. It's just enough of an overview that if you're totally new to functional JavaScript, or just need a quick refresher, you'll have something to stand on so you can understand the benefits provided by the libraries we're going to cover in the course. But first, a little warning. Now this may seem a little odd in a course touting the benefits of a particular technology, but I would be remiss if I didn't mention this. Maybe it's just me, but it seems that the JavaScript ecosystem is extremely susceptible to Shiny Object Syndrome, the tendency to jump on whatever the new bandwagon of the week is. Functional JavaScript is certainly suffering from this problem over the last few years. I'm not saying not to look at it and potentially make use of functional JavaScript and the libraries we're going to be looking at in this course, I'm just advising you not to jump all over it and rewrite your code base using it. Look for places where the benefits of functional JavaScript would add value and introduce it there. I can't see any value in going back and rewriting any working code just to add functional JavaScript tenets to it. But if you're starting a new project or reworking an existing project to add new capabilities or fix some bugs, look for places where functional JavaScript and these libraries in particular add some value and consider adding them. Looking for those places where functional JavaScript and specifically the libraries we're covering provide value is the primary focus of this course. As long as you keep your focus in mind as you go through the course and your exploration of functional JavaScript, you'll be okay. So, why functional programming? I can sum that up in three very high-level buckets. First, functional programming tends to be very predictable. For reasons we'll see throughout the rest of this module, when it's done, it's very easy to determine what's happening and where it's happening at any given point in your code. Given a set of inputs, the output is always the same for a function, regardless of what's happening elsewhere in the code. Second, we're going to talk about composability in a bit, but one benefit of that is that functional programming tends to be highly modular, far more so than a typical object-oriented programming approach. We can snap together pieces of a functional code base quickly and easily to deliver the functionality we need. Finally, because of pure functions and immutable data, which we'll cover in a moment, functional programming is safe, or side effect free, meaning that things aren't going to be changing in unexpected or unanticipated ways. Touching upon the predictability already mentioned, functional programming is very deliberate. Let's dig into a couple of key terms and concepts from the functional programming world and break these three areas out further. The six key things to know about functional programming are pure functions, composition, higher-order functions, currying, immutable data, and closure. Once you understand these things, you're well on your way to grokking functional programming. So let's take a look at each with some examples. Pure Functions For a function to be pure, it means three things. It can't have any side effects, meaning nothing outside the function changes. It must always return the same output for a set of inputs, which kind of implies that it has no external dependencies. So, for example, it can't make use of a value not passed into it as a parameter to perform part of its work, because that external value could change, which would mean that the function is likely to return something different. Let's go take a look at some examples of pure and impure functions. So this code here, is it a pure function? What do you think? Well, yes. It passes all of our tests for pure function, so it's a pure function. That was pretty easy. How about this one? It only passes one of our three tests. It has a dependency upon the external variable c, and so it won't give the same output if c were to change. So this one is not pure. This one? This one's similar to the last, but this time its external dependency is on func1, so this one isn't pure either. Are you sensing a pattern yet? This one isn't pure because it has side effects. It changes the value of c, which is outside of the function. So it fails. Also notice that it doesn't return anything, which isn't technically enough to make it an impure function, but if pure functions don't return anything and can't change anything outside of itself, why exactly are you calling it? It's just wasting cycles. How about this one? This one isn't pure because it also has side effects. It changes the console. Technically that's an external dependency as well. Again, notice that it doesn't return anything, a good sign that you might have a purity problem. Last one. You've probably guessed that this one isn't pure, but why? Yeah, it has a dependency on something outside of itself, func1, and can't be sure that func1 doesn't cause a side effect. So that counts as a side effect for this function. So not pure here, either. Hopefully those quick examples help you understand pure and impure functions. To wrap things up, just a few final thoughts about pure functions. Pure functions not having any side effects means that they can't be used to change anything in the user interface, namely the DOM. That would be something outside of the function. That means you need to separate out any UI updates and keep them separate from your pure functions. As I alluded to, a pure function that doesn't return something doesn't make any sense. It can't impact anything outside of itself, and so if it doesn't return something, what's it doing? In addition, whatever's calling the pure function should always make use of that return value in some way. If it doesn't, what was the sense of calling the function to begin with? Now note that using the return value could simply mean storing it for later or checking if it's undefined in branching appropriately, et cetera. It doesn't mean that it needs to immediately do something with the returned value. One more thing along these lines, and this isn't a hard rule of functional programming, it's just a thing I like to do and something you'll see in lots of functional programming. I never return undefined or null from a pure function. If the function could in certain circumstances return a widget, I like to always have it always return a widget, never undefined or null. I'll then have something like an is valid property on the widget that tells the calling code whether that widget is okay to work with. Again, not a strict tenet of functional programming necessarily, but a good practice I think. The only variation on this is if I'm working with a library that supports maybes. In that case, I'll use the library to return an object or maybe.nothing or maybe.none, depending on what the library calls it. We'll touch more on maybes in the libraries that support them. The last thing about pure functions is that they're extremely easy to test. They take all of their dependencies as parameters, have no side effects, and always return something, so writing tests is easy. Composing Functions One way to think about function composition is that it's the snapping together of functions to deliver the outcome you need. This is a functions as building blocks approach. But another slightly different way to think about it is that composition entails creating a process or a machine where each function is a piece of that machine. When the machine runs, you supply inputs and get predictable outputs. Whichever mental model makes more sense for you is fine. In either case, the idea is that functions are small, reusable pieces of functionality that alone may not seem like much, but together they make up the bulk of your program. In the demo, we're going to take a look at some real-world composition based on a product that my company is building, so let's go take a look. Taking a look at composition, all of the data we're going to work with is in this people.json, and you can see it's just a collection of person information, so that's all the data that we're going to be working with. We're going to work in this file composition.js. We have a little bit of supporting information just to clear the console as it runs, and then just to output whatever we've stored in that out variable, and then just the number of records. So, just get those out of the way, but I wanted to show them to you so you knew what was in there. Now if we go ahead and start up nodemon and point it at this composition.js, it's going to run node for us, and you can see we get out 10 records, it's just exactly what we saw inside the people.json file. There's no filtering going on in here. We want to start doing some filtering, so we'll paste in a little bit of code here, and as you can see, I have two different filters, a filter equals and filter not equals. Nothing special about these, these are just using the array filter method that comes with, built into JavaScript. Well, what we're going to do is we're going to build upon these and ultimately start composing some functions. So we'll paste in a couple of additional filters. These are each calling the filter equals, filtering on the married property, either true or false. Again, nothing particularly special about this. Take in an array, and they specify two of the values, married and true or married and false. We can do the same thing with gender, to be on a filter for men or women. You can see we have one example of using the not equals filter, with the rest I'll use filter equals. So now to see the effect of one of these, let's change our output to say show me just the married people. So you can see I have four people listed as married. That means if I run filterSingle, I should get six people. So here's the filter for just single people. I could do the same thing with men and women, but this is going to give me the ability to apply those filters, and now all I'm doing is specifying just the array that I want to do the filtering on. Applying women, I've got five women, and that means I ought to have five men as well. So just some basic array filtering. We haven't done anything about composing yet. That's going to come up next. So we're going to paste in our next set of filters, and now we're going to start to group two of our standard filters together. We want to be able to get married women by composing the filter for women and the filter for married. Okay, we get them both applied. Now in order to do this, I need that compose function. So just insert that here. And this is pretty good for composing for straight JavaScript, it doesn't handle exceptions, there's nothing in there that would handle an edge case, but for the sake of just being able to demo composition, that works pretty well. So now I can see I've got three married women, that's composing the filterWomen and the filterMarried. That means I should have two single women, composing filterWomen and filterSingle. Same type of thing for marriedMen and singleMen. I have one married man, which means I ought to have four single men. So that's what composition looks like. I'm taking existing filters and combining them together to get the results of all of those filters being applied. FilterWomen, filterMarried, filterMen, filterMarried, filterSingle, et cetera. Some final thoughts on composition before we move onto higher order functions. Composable functions should do one thing and one thing only. Grab bag functions that do a bunch of stuff are not composable. Functions should be named appropriately for that one thing. This is a good way to help ensure your functions are only doing one thing also. If your function name has the word and in it, then you're not doing just one thing. A function name of set surname and lineage tells us right away that we're doing too much. We should break that down into two functions. Set surname and set lineage. This is also a form of documentation. We know exactly what each of those functions do, and should be able to expect that they do nothing else. If we're debugging and there's a bug in a person's lineage, we don't need to bother looking at the set surname function. We're know we're going to have to focus on the set lineage function. As a side note to this, I think it's a good practice to have good descriptive function names. I don't worry too much about the length of my function names. Within reason, of course, longer and more descriptive is better. Perhaps this goes without saying, but I'm good at stating the obvious, so I'll mention it. Be default, composable functions are going to be chained together when they're used. In other words, the output of one function is going to be sent right in as the parameter of another function without any type of intermediary storage. This is another reason why you want to avoid returning undefined or null from a function. Higher-Order Functions Higher order functions is one of those big scary terms for a really simple concept. A higher function is simply a function that either takes another function as a parameter or returns a function as its return value. That's it. Pretty simple once you know that. In fact, because it's so easy, rather than jump over to our demo machine, here are a couple examples of incredibly simple higher order functions. The first simply takes in a function and a parameter z and returns the result of evaluating the function and passing in the fixed string dave and the value of z. The second returns a function that takes a single parameter and logs to the console the word hello and whatever that parameter is. The result in this case is simply hello dave with an exclamation point being logged to the console. This is functionally equivalent to a single function like this. With simple examples like this, it's a little hard to see why we care about higher order functions, but we'll see why when we get to currying in just a moment. Currying – A Spicy Look at Functions Currying is the act of taking a function which accepts 1 to n parameters and producing a collection of 1 to n functions, which each take 1 parameter. Looking at this simple example, if we even add function, which simply returns the sum of two parameters passed to it, we can curry that and produce a function in which we've eliminated one of the parameters by essentially hard-coding one value. This new curried function add 5 can now be used to add 5 to any value, as you can see here, with the expected output of 6. Overly simplistic examples such as this are useful to explain the basics of an idea like currying, but I think they fall short when trying to really grok something. Understanding the basic concept of currying is easy once you've looked at an example like this, but to really get it you need to see something a bit more real-world, so in just a moment we're going to look at some real-world examples of currying in our demo. But first a quick side note about an often confused and similar term. This is really just for the purists out there, so it's not something to be overly concerned about. Partial application is executing a function with less than its full set of expected parameters, and hard-coding one or more of those parameters. But nothing about partial application says the new function can only have one parameter. Contrast this with the definition of currying from the last slide in which we said that we end up with a series of functions each taking only one parameter. Here's an example of partial application that's similar to the example we used for currying. Our sum function takes 3 parameters. Sum5 is a partial application of that, which takes 2 parameters, and sums them along with the hard-coded value of 5. This is partial application, not currying. As I said, nothing to be overly concerned about, just tuck it away in the back of your head that there is a difference. Now let's go take a look at some examples of currying. Taking a look at currying, we're going to start from where we left off in the composition.js. All I've done is taken all of that code and copied it over into this file curry.js. So we still have our filter functions, filter equals, and filter not equals, we still have compose. I'm going to get all of these filters out of the way, and then we're going to go through and build our own functions that we're going to manually curry. So we'll start with an isMarried function. It'll take a value and an array, and it will then call into filter equals, pass in the property of married, whatever value was passed into isMarried, and then whatever array was passed into isMarried. So now we've gone from three parameters on filter equals to two parameters on isMarried. So we've removed one of those parameters. Now we're going to create another function here that we'll call married. That's going to take a single parameter, just the array, and it's going to make a call and do isMarried, pass in a value of true, and whatever array it was given. Similarly, we can create another function here that takes an array, calls into isMarried, and passes in false. Now when we're going to write this to the output, we can call that married, and all we need to do is pass in the single array parameter because we've manually gone through and curried from filter equals with three parameters to isMarried that takes two parameters to married or single that take just one parameter. So that's showing going through and doing manual currying of our functions. Immutable – Can’t Touch This The concept of data immutability is easy. You can't change immutable data, period, full stop, end of story. In practice, of course, we have to be able to modify the data in our application, so that's where things get tricky. Instead of changing data in place, immutability requires that we create a new instance of the data with the updated values and use that. That sounds like a lot of work, but before we really dig in and discuss immutability, let's very quickly talk about why it's important. Really it comes down to performance. If you have an object and need to change the value stored in one of its properties, it may take a long time for JavaScript to recognize that that property is changed. Basically every property on that object has to be checked to see if it's changed in order to determine that our data has changed. By enforcing immutability, all JavaScript has to do is check the object reference to see if that's changed. If it has, that means that some property value is changed. Checking for object reference changes is unbelievably fast. So in that sense, immutability is a performance enhancer. Okay, now back to actually implementing immutability. It's important to note here that this is primarily working with objects and arrays. Strings, numbers, and Booleans in JavaScript are already immutable. So what does it mean to have an immutable object or array? Let's take a look at an example of immutable objects, realizing that immutable arrays would be similar. If you have an object that looks like this, immutability says you can't do this. Instead, you have to do something like this, where a call to setProp returns a new object, so it might look something like this. It creates a new instance, deep cloned from the original here using lodash, but anything that will do a deep copy is fine. Sets the updated the value in that object, freezes it so it can't be changed in the future, and then returns that new cloned frozen object. We're not going to jump over and take a look at a demo for immutability, the example on the screen is a good example of the type of code you would need, and we're going to take a look at a library that can help with this, cleverly called Immutable.js, just a little bit later in the course. There are obviously performance implications to immutability and deep cloning like this. We're going to take a look at demos in the module on immutability.js, so I'm going to hold off for now. Just know that by using a library like immutability or writing our own code, there are ways to avoid those performance problems. Closure Without Grief Closure sounds like something developers need when they break the build. The final step of the grieving process. But that's not what we're talking about here. In this case, we're talking about function closure. Or to use big fancy words, lexical scoping. In any event, the idea is way simpler than the terms make it seem. If you have a scope, for example, a function, in this case represented by our orange square, which defines a variable, here the triangle, then any function also defined inside the orange square, such as the blue circle, can access the triangle. So far that's just pretty standard block scoping. A function can access any element defined by its parent. Closure comes in when you take the inner function and reference it from outside its parent scope. So now we have a variable outside the orange square that references the blue circle. Even though we're outside the scope of the orange square now, we can still access the triangle, even though it isn't defined inside our circle function. The reference to our circle function forms a closure. It wraps the entire lexical or execution environment of the circle function and carries it along with the function. Translating this shape example into code would look like this. I've named the elements to correspond to their shape counterparts to help everything click together. This is going to be used in currying among other places, so let's take a look in our demo. Taking a look at closures, we're going to use the same code that we used inside the slides, so we have our orangeSquare function, we have our outside variable that points to or gets the result of orangeSquare, and then we just call that outsideVar function. And you can see over when we run node, we get hello from inside. If I were to try to uncomment this console.log for triangle, you're going to see we get a reference error, triangle is not defined. That's because it's enclosed inside orangeSquare, I can't get at it from outside. The only way I can really access it is by calling the outsideVar, which has a closure around orangeSquare, so it has access to triangle. Otherwise, triangle is not available to me. A Visit to Fantasy Land (the Spec) Fantasy land was first published to GitHub in April 2013 by Brian McKenna, and since then it's been expanded and built upon by a number of other contributors. It builds upon specifications used by other functional programming languages, so why do we care? Primarily we care because it provides a basis for taking concepts that aren't native to JavaScript and providing a framework upon which to build them. More specifically it provides a framework upon which different libraries and our own custom code can rely to provide interoperability. Which is why the Fantasy Land specification calls itself "specification for interoperability of common algebraic structures in JavaScript." Aw man, this sounds like math! Algebraic structures? Really? This diagram isn't helping. Most of the things on here sound like they're from a bad science fiction or superhero movie. Sum of the return of monoid, bifunctor versus semigroupoid. My brain is starting to hurt. Fortunately, it's not as hard as you might think. At the very least, we can tackle it in small chunks. Going back to this slide is really just one structure we need to start with, the monad. Not that the others aren't important, just that monad is the one that pops up most often when you're reading about functional programming and getting started with it. So we'll start with monad. We can skip its immediate parents, applicative, chain, and apply for now, but we do need to discuss functor in order to understand monads. So let's start there. First things first, I'm not looking to provide a perfect textbook definition of these things. I'm far more interested in making sure you understand the concepts, enough to actually make use of these things when you need to than I am having you be able to spout off a perfect definition. For our purposes, the Fantasy Land specifications defines interfaces. So a functor is something that can be mapped. That is, the interface defines a map function, which takes a single function as a parameter. As far as we need to worry about for now, that's it, that's what a functor is. Any Fantasy Land compatible code, whether it's ours or a library, that expects a functor as a parameter or returns a functor, is going to mean something with a map function. That's the value of a specification like Fantasy Land. Now, a monad. A monad is a type of functor, which means it has a map method. In addition, you can think of it as a container, a wrapper around a value if you will. And that container provides a means of getting a value in and out. It may not sound like that's something you'd have much use for, but here is the thing. You're already using monads. You just don't know that's what they're called. This is the reason. Promises and observables are monadic. Neither is the value you actually want, but each wraps that value in some way and provides a way to get the value into the promise or observable and back out again. I already mentioned promises and observables and being monadic or monad-like, so we're going to skip past those. Later in the course, we're going to introduce several monads in the context of libraries that support them. Primarily these will be the monads maybe and either. So that covers what you need to know about the Fantasy Land spec, at least to understand the references later on in the course. As I said at the beginning, I gave preferences to libraries that made at least an attempt to follow some aspects of the spec or had such work in progress. If you'd like to read the spec itself, it's available here. Be forewarned though, unless you're into some heavy-duty math and category theory, it's not exactly light bedtime reading. So that's it. Functional JavaScript 101. If you've got this handful of things down, you're ready to dig into some functional libraries, understand what they're all about, and see how they can provide some value. Just remember to ignore the hype and look for places where aspects of functional programming can provide some real value in your projects and everything's going to be okay. The next thing we're going to take a look at is the Immutable.js library from Facebook that I had mentioned when we were talking about immutable data. Choosing a Library Introduction It doesn't make any sense to use all of these libraries at the same time as there is so much overlap between them. So, how do you choose which library to use or which libraries are complementary and can be used together? That's what we're going to cover in this module. We're doing this before looking at the individual libraries, so perhaps you can save a little time and focus in at least initially on the libraries that look the most interesting and most applicable to your situation or needs. Primarily I'm going to be considering these aspects as I compare and contrast the libraries. The functionality offered by each library, how active they are both in terms of commit history, but also active issues, responsiveness to questions, et cetera. Some of the libraries are not very active on the commit history, for example, because they're essentially mature and don't change very often. But they're still very active in terms of answering questions and resolving issues. We're going to look at interoperability to see where holes in one library might be able to be filled by capabilities from another library without causing problems. And finally, I'm going to consider how easy it is to get started with a given library. A lot of this is going to be the documentation for the library, but it also factors in the availability of third-party blog posts, perhaps providing walk-throughs and such, as well as the responsiveness of the team behind the library to questions and issues. I'll say this right up front, this is a decision you have to make for yourself or as a part of your team. I'm going to try really hard not to let my biases or preferences come through. They will, of course, but I'm intentionally not making an out-and-out recommendation for a given library, primarily because I have no idea what your situation or needs are. I'm going to present the information as neutrally as I can, and then it's up to you to decide. But here's the thing. None of these are bad libraries. They each have different strengths and weaknesses, but none are bad. Also, remember this is my take on things. As much as I'm not expressly stating an opinion, the simple fact that I'm highlighting certain things in each library means that I'm focusing on the things that are important to me. Different things are going to be important to you. The Big Overview Slide So here's my big information overload slide comparing the libraries. I'm not going to go through each and every point here, just hit some highlights to explain what I was looking at for each row. And remember, this is entirely subjective. If I came back to do this slide over again, even a few weeks from now, it would almost certainly look different. But for right now, this is how I view the libraries. Currying. Everything except Immutable.js provides some currying functionality. Ramda goes a step further with its automatic currying and general flexibility. Compose. Again, nothing from Immutable.js, as it isn't in its scope, but all of the others provide functions to support composability. Again, Ramda is the most flexible here. Immutability. Naturally Immutable.js wins here. Everything else supports immutable data, but doesn't provide the data structures and level of support the same as Immutable.js. Documentation. This one was a bit hard because in general, none of the libraries have what I would consider great docs. Folktale got an extra star just because while it's still not great, it's arguably the best of the lot. Interoperability. Generally I'm looking at a general sense of whether a particular library appears to have been written to play nicely with others. This is both whether the library is small and focused or big and monolithic, as well as whether it sticks closely to standard JavaScript data structures or defines its own. Fantasy Land. Where applicable, a sense of whether the library looks to the Fantasy Land spec for guidance. This varied from Immutable where it doesn't apply to strong adherence and sanctuary and almost accidental interoperability in FKit, meaning it doesn't expressly mention Fantasy Land, but does provide some support nonetheless. Maybe/Either. Three stars for support, none for no support. Ease-of-use. I was trying to capture a general sense for how easy it was to get started and continue working with the project. Some of the these libraries I started with quite awhile ago and others were new to me. But I kept copious notes as I investigated each library, whether it was two years ago or last month, and I did my best to normalize my experiences as I've gotten more comfortable with functional programming in general. I've mentioned this before, but this is a general look at whether the project is still active, commits issue resolution, team responsiveness, etc. And last, completeness. Again, subjective. But a look at whether the library tries to check all the boxes or focuses on a smaller, more targeted subset. As you're looking at the chart, just remember this, and this. How Do I Choose? Now let's take a look at how you can start to narrow the field and decide on a library or libraries to work with. The first decision is whether or not you want to pick just one library or go for a combination. If you go for one library to provide all functionality, I think your choices are, in no particular order, Sanctuary, it's arguably the broadest from a functionality point of view, but while the team is quite helpful, the learning curve is not insignificant. Next, maybe you'll look at Ramda. From a number of functions available point of view, it's a little broader than Sanctuary, but it's missing a maybe construct. We'll address that in just a moment. And finally, Monet. This is a very minimalist library, but it provides a good breadth of functionality. My biggest concern here is really this support for the project moving into the future. I just can't get a good sense for how this library will look, 12, 18, 24 months down the road. That said, to a certain extent, that may not matter, as it's open source. So if Monet works for you or your team, simply fork it and continue, naturally looking to support the original library as much as you can, but you're not prevented from extending and fixing the library as you need. If you'd rather take a best of breed approach by combining libraries to provide the functionality you need, here are some options, again in no particular order. Just realize that for each of these you're going to have some additional work to do to make them all work together as a single solution. Ramda for most of the functionality, then maybe/result/validation support from Folktale, and Immutable.js for immutable data structures. This offers pretty much everything you could want or need, but, and this isn't a small consideration, you're combining three different libraries here. This may not be trivial once you get beyond the basics. Next, just drop Immutable and have Ramda and Folktale. You're then on your own for ensuring immutability for things outside of Ramda and Folktale, but that may be easier than adding a third library, and may just be good enough. You'll still have some work to do to combine two libraries, but it's certainly less than combining three. And the last combo I'll mention is FKit and Folktale. FKit is more minimalist than Ramda, but if you don't need all of that extra stuff, then it's likely going to be easier to integrate FKit and Folktale. You're still combining libraries, but it should be easier. One final twist on this is the eventual availability of the Sanctuary, Maybe, and Either structures as standalone projects. Right now, mid-2018, they are only available as part of the monolithic sanctuary project, but the team is getting ready to split them out. I think that would only change the combinations shown here for Ramda. Since Sanctuary is based on Ramda, it may be easier to integrate Sanctuaries Maybe with Ramda than Folktales Maybe. This is pretty obvious, but I'm going to mention it anyway. The things you need to take into consideration when you're looking at these libraries include team size. Can you split your team up and have each group look at one library and then report back? Or do you have to do all of it yourself? Project size/duration. If you're looking to add one of the libraries to a one-month project, you probably don't want to pick one that's going to require three weeks of ramp-up time. Unless you're looking to define a standard for the team that will be used on most or all projects, then the ramp-up time isn't just for one project, it's for all future projects as well. And finally, the experience of your team. Things will look very different for a team with very little JavaScript or functional programming as opposed to a team of ex-Haskell developers with a few years of JavaScript under their belts. To wrap this up, the only recommendation I can safely make is that you look at all of the libraries, including perhaps some I didn't mention in the course, and try them out. Give the ones that look interesting a small test run, either with a made-up test project or a small project that will go into production. The only way to know for sure which is the best library is to kick the tires on a couple of them. ImmutableJS Library Overview We're going to start with a library that's a little different from the others that we're going to cover later. Immutable.js is a library from Facebook. It's not a functional library per se, but it does provide immutability, hence the clever name, so it comes up a lot in discussions about functional programming. And if none of the other libraries that we're going to talk about later do it for you from a functional programming point of view, this library would provide a great basis upon which to build your own functional programming utilities if you were so inclined. We're going to zip through the slides as quickly as we can so we can get to the code. There are a few concepts and such that I need to introduce before the code will make much sense. The official website for Immutable.js is this URL. Off to the left there, you can see its wicked cool retro-80s style logo, too. The official documentation for Immutable.js is available at this URL. But here's the thing. The official documentation, let's just say that it leaves something to be desired, or more so it leaves a lot of something to be desired. Especially if you're just getting started, you're going to be much better off working with what a lot of people are calling the unofficial documentation available here. The primary difference is that the official docs are just a listing of the API specs with very few examples. The unofficial docs, on the other hand, while not covering the entire API, provides plenty of interactive examples and a much better organized approach for coming up to speed with Immutable.js. We're going to cover enough of Immutable.js in the demos to help you get a sense of what it's all about and how it works, but if the introduction peaks your interest, I'd recommend your next step being the unofficial docs to round out your understanding, and then you'll be ready to dig into the final details in the official docs. Looking at the strengths and weaknesses of Immutable, the big obvious strength is that it guarantees immutability of any data you use it to manage. It would be kind of silly if it didn't do at least that. Now one of the big concerns most people have when you start talking about immutable data is performance, which makes perfect sense. Deep copying large objects or copying large arrays to ensure immutability is a potential performance killer. The team behind Immutable was well aware of this as they built the library and took an approach to eliminate the problems right from the start. The typical term used for this approach is structural sharing, and we'll be taking a look at that in just a minute. For now, just know that by using it, Immutable.js delivers more than acceptable performance. Finally, to bring a real-world scenario into this, Immutable.js and really immutable data in general is fantastic for state management. Whether you're using something like Redux or ngRx or rolling your own state management, immutable data is a natural fit. Now let's go and take a look at some weaknesses of Immutable.js. First, if you're dealing with other aspects of your data that are not aware of and able to function with the data structures used by Immutable.js, you're going to have a lot of converting to and from immutable data structures and standard JavaScript arrays and maps and such. There's not a whole lot you can do about this except be aware of it, and look to minimize that thrashing. That means things like doing as much filtering and sorting with Immutable.js before you convert over to an array. This helps to ensure that you're only converting the minimal amount of data possible from an immutable to an array. The next drawback to be aware of is that there's going to be a small learning curve for working with Immutable.js. Some of this is the standard I'm using a new thing learning curve, but some of it is syntactical. For example, Immutable requires a non-standard syntax for working with properties of an object. We'll take a look at that and more in just a minute. I've already touched on this, but just to mention it here for completeness, Immutable.js's documentation needs some help. Let's go take a look at two things in a little bit more detail before we move onto some demos. First, the weakness because it's quick. In Immutable.js, you can't use dot-notation or brackets to access object properties. You'll always get undefined if you try. We'll see this in the demos, but essentially you have to use functions to get, set, or update properties. In other words, you can't do this, you have to do something like this. Once you get used to it, it's not bad. You'll still slip up and start typing the dot, but it's an easy recovery. And now the performance boost we get using Immutable.js that you wouldn't get just cloning copies of things the regular JavaScript way with something like object.assign. Structural sharing is a big fancy term for essentially just reusing existing elements whenever possible. Starting with a simple object, we might represent that in pictures like this. Well now we have some additional information. We're going to add Henry Ford's son Edsel. Again, visually it might look something like this, highlighting the element that changed. Maintaining immutability, we can't do this, because that changes our original object, which is a no-no. So we're back to this. But this duplicates everything, which wastes memory and takes extra time for all that copying. Instead, with structural sharing we have our new object, maintaining immutability by not changing the original, and we add the new or changed data. But then instead of copying the unchanged data, we simply point back to it in the original object. The end result is the same, but we only had to duplicate one-third of our data. Much faster and requiring less memory. When we no longer need that original object, the garbage collector will clean it up, except for the pieces our new object has references to. So we avoid additional memory pressure here, too. Now just remember, this is a representation of what happens in PowerPoint. It's not exactly what's happening inside the VM, but it's close enough to get the idea across. Getting Started and Common Operations We're just about ready to start looking at some code. First, a quick look at getting started with Immutable.js. You get the bits with yarn or npm, require the library, and that's it. You're ready to start writing code. Immutable makes a handful of data structures available to us. We're not going to look at all of them, just enough to give you a sense of what the library is all about. This means we're going to look at lists, you can think of them as JavaScript arrays on steroids, maps, or essentially JavaScript objects, and then we're going to look at how we can work with nested entities, which is important because when you create a list or a map, by default they're shallow copies. You're only going to get immutability one level deep. If you want immutability all the way down, that's when working with nested objects comes into play. We're going to take a look at all this in the demos, so let's jump over and take a look. Immutable Data Structures Taking a look at Immutable.js in Visual Studio Code, you can see we have a couple of things set up here already. I'm requiring immutable. I'm also requiring a people.json file, which is the data we're going to use through most of the demos in this course. We take a look at people.json, it's just a listing of information about people, sample information created for the application my company builds, but we just grabbed some of that sample data and are using it for, like I said, most of the demos inside this course. Back over in Immutable.js, we're setting up, clearing out the console, giving us some space. We're setting up a variable called output. This is what we're going to be writing out to the console. Down below that we're just logging out that out variable and then giving us some space again so we can see the results of each test run. So inside here is where we're going to be putting our code, and I've got some snippets set up that I'll be just pasting in and then we'll talk about them. Starting with some information just to get a sense for how we work with the different data structures inside Immutable, you can see we're just, we're not using the people.json for this yet, we will be in just a bit, but we're just setting up a list of a and b. So we're taking an array and converting it to a list. I'm going to start up node using nodemon, and then I just go ahead and save, and it's going to give me what my output is. So you can see it's just a list of a and b converted from that array. I can do the same type of thing for a map, so you can see what a map looks like. Now I've mentioned before about nested objects, and here is where that starts to come into play. You can see when I look at my map now I have a, b, and then c as an object. So it doesn't go and create anything, it doesn't touch that nested object there, so we don't get d 123, we get a with a value of b and c with a value of an object, so that object is not immutable. If we take our people array, you can see how that gets a little bit harder to work with. We now have a list of immutable objects. So in order to be able to get those nested things to be immutable, we need to use this fromJS. So now when I go and run this, it's a little hard to see, but everything has been converted to those immutable data structures, list and map. Starting up at the top here, you can see we have a list, and inside that list I have a collection of maps. So here's the first map, then we have another map, and a third map, so you can start to get the idea, but then also inside those maps we have some nested lists. So givenNames is an array, so it is a list inside our map. Some of the people are going to have a nested map inside their map, so we have family here as a nested map. So you can see how by using fromJS we're able to get that immutability all the way down, everything inside there is converted into an immutable data structure. If we want to take a look just a little bit less data, and you can see here's what just one person looks like, because I'm using the first function on my immutable data structure. If I want to start to work with that, this is where I was saying that we can't just use the dot or the bracket notation, we have to use get. If I want to get the surname of the first person, then I call iPeople.first.get, and then I pass in the surname, and then I can pass in a default as well. So if there is no surname listed on the first person, I'm going to get none in parentheses. Same type of thing when we're working with maps and we're going to be going down into following a path down to the property we want to get to, we use get in. In this case, we pass in an array of path names or path values, so we're going into the family map and getting the fatherId property. And again, I can specify a default, but in this case, the fatherId in the family map for the first person has a value of 2, so I get that value instead of none. So that's a quick look at how we would go about working with some of the immutable data structures and creating some of those structures. We're going to be taking a look at that further as we work through the rest of the demos in this module. Filtering on Top-Level Properties Starting to work with some of these immutable data structures, we can go in and start to apply filtering. So you can see here we are working on our iPeople data structure that we had created earlier. And we're setting up this filterEq that takes a propName and a propVal and it returns a function that takes a data parameter and then applies just a regular filter to it. Pulls out anything where propName equals propVal. So we can set up that filter. We can also take this one step further, and this is manually currying these to set up filters for particular properties. So here you can see that I'm filtering, passing into my filterEq property name of married and a value of true, that's going to give me something back, a function that expects now to just be passed in data. So I can now use that married function to say give me just the married people. And there are the people that are married. So that's a way that we can start to apply some of the common operations that you typically need to do on datasets using the immutable data structures. It's not that different from anything we've seen working with arrays or anything we will see later working with the other libraries. Filtering on Nested Properties Continuing to look at filtering, we can also start to apply filters on paths. So we can work with those nested immutable objects. Here we set up a function filterPathEq, we pass in propPath as an array and propVal, and we return a function that takes a data parameter and applies the filter using itm.getIn and passes in that array path. So this is using getIn and a path and array of strings that takes us down to the property we want it to filter on. So we can set up a filter for fatherIdIs where it's going to return us a function that takes an ID and call that filterPathEq, passing in the path down to fatherId, family, fatherId, as an array of strings, and then the ID we want to filter on. So then we can take that one step further and say we frequently want to pull up the person whose fatherIdIs2, so we can set up a function that supplies the ID, and now all we have is a function that we need to pass in our dataset to. So we can call fatherIdIs2 and pass in our dataset and we're going to get back just the person whose fatherIdIs2. So again, taking a look at filtering, this time working off of nested maps inside our immutable data, we can still go in and do filtering on those and set up the functions to filter on specific property values nested inside our immutable data structure. Updating Data So far we've just been looking at filtering our immutable data structures. So how do we go about updating something? First thing we're going to need to do is actually find the item that we want to update. The index to that item inside our list is going to be part of the path, so we need to get the index of the item. So here you can see we set up a way to get that index. We're looking for, again, the person whose fatherIdIs2, so we're using the findIndex function on our immutable list iPeople, and it's going to give us back the first person whose fatherIdIs2. So now as I said, that's part of our path to the particular item that we want to update, because we want to get just that one thing now. So to actually do the update, we have a couple different ways we could do this. And remember that what we get back is going to be a different structure because we do not make any changes to our iPeople, we're going to be getting an iPeople2 as a different structure, and it's going to be a different list of people, and that will contain our changes. So we set up iPeople2, we do a check to see if the index is -1. If it is, we just get iPeople back unchanged, so iPeople and iPeople2 are going to be the same at that point. But if it's not -1, then we're going to use the setIn function on our lists, remember how I said we need to pass in the index, so that's the beginning of our path. That tells us which item inside the list are we going to be changing. So we pass in the index, and then we want to go to family and fatherId and change that to 321. So now if I take this and go ahead and run it, and I'm going to use that fatherId as 2 on iPeople2, I get back an empty list. Because iPeople2 doesn't have anybody with an ID of 2 for their fatherId because we've changed it. And that change is stored in iPeople2. If I take that same fatherId as 2 and run it on iPeople, my original list, then I'm going to get the person back, because that has not been modified, that's the idea behind immutable data. Now I want to call out also before we go any further that we have two options for changing a value. We've been looking at setIn, which allows us to specify the actual value that we want to change, so we're completely overriding what's there. We also have the option of doing updateIn. UpdateIn is going to give us the ability to work with the value that was there originally and apply some function to it. So here you can see that we're taking the value that it's there, 2, and we're adding 319 to it, that gets us to our same 321 value. And I did that just so we could use the same functions that we have set up here. But two different ways to go about changing an item inside our immutable. If we're just going to overwrite whatever is there where you setIn, if you want to use what's there to calculate a new value, then we can use updateIn and apply a function. We pass in that function that allows us to determine what the new value is. So continuing on, if we want to take a look at our actual change, we need to go into iPeople2. And that's where we see the changed value. So we've gone and made a change to our data structure, but we get back the changed structure. We saw above that the original structure is not changed. And that's the idea, like I said, to immutable data. Once we're done working with iPeople, if we don't use it anywhere else, the garbage collector is going to pick it up. So we don't need to worry about wasted memory. So that's a look at some of the basic operations for Immutable.js from Facebook. Like I said, if you wanted to dig into this, if this looks interesting, you want to take a look at that unofficial documentation before you start to take a look at the official documentation. The official documentation will make a lot more sense once you've gotten some experience that you can get through the unofficial documentation. Ramda Library Overview Ramda is the first of the truly functional libraries that we're looking at. We're going to get through all of the introductory material as quickly as we can so we can spend more time looking at some common operations in our demos to really help you get an understanding of what this library is all about. But I do want to spend just a little bit of time on some of the introductory stuff, just so that the code makes more sense later. Ramda builds itself as a practical functional library. It consists of over 200 different functions that cover a lot of useful capabilities. Information about Ramda is available at ramdajs.com. Ramda is essentially built on four pillars. If you know and understand these, you're well on your way to understanding Ramda. After this it's really just a matter of getting comfortable with the API. Those four pillars are immutability. All Ramda functions return a copy of data structures provided as parameters. The original structures are left unchanged. Automatic currying, though Ramda also provides a manual curry function if you need it. Side-effect free. As we discussed in the functional 101 earlier, Ramda's functions have no external dependencies and don't make changes to anything outside the function itself. And last, all Ramda functions are data-last, meaning that the collection or array of data they operate on is passed as the last parameter. This helps to facilitate the automatic currying, and as you'll see it's a powerful approach to simplifying your functional programming. When I was first learning about Ramda, two things that I read on their website resonated with me. This is the first, the API is king. We sacrifice a great deal of implementation elegance for even a slightly cleaner API. I like this because it's something I've long believed. The external face of your code is far more important than the internal workings. A really powerful API is one that's easy for implementers to use. Simplicity in the API is far more important than simplicity, cleverness, or elegance of the internal workings. And this is the second. This one struck a chord because I agree with the idea that adherence to an ideal or a spec is something worth striving for, but the real world has to intrude, and in the real world, no one actually cares how closely you adhere to any spec if your code is ugly, bloated, and slow. So Ramda strives for performance. A reliable and quick implementation wins over any notions of functional purity. If you haven't guessed, I like Ramda. I've used it on several projects. That doesn't mean I have blinders on about it, though. Like any library, Ramda has its strengths and weaknesses. Here's a look at what I see as the strengths and weaknesses of Ramda. Realizing that these are entirely subjective, let's start with the strengths First is the sheer breadth of the library. It has something north of 200 functions currently and covers just about everything I wish it would. Despite that, it still feels very focused. There isn't really anything I look at in the API and say it's an oddball, something that doesn't fit in with the rest. Consistency. The team has done a good job of maintaining the internal consistency of the library, which makes it significantly easier to learn despite its breadth. Once you get started with the library, getting comfortable with new functions is an incremental process, as everything is put together similarly. And last, the Ramda team itself. Like most, if not all, successful open source projects, there's a core group and then a larger group of supporters. The team is responsive and the project is actively maintained. And now the weaknesses. First, partially due to its breadth, the learning curve for Ramda is a bit steep, especially if you're simultaneously coming up to speed on functional programming. Another reason for the steep learning curve is the documentation. Don't get me wrong; the documentation is incredibly thorough and easy to work with once you're comfortable with Ramda and functional programming. Until then, it's a bit muddy. It's just API documentation, all of the different methods, but no real getting started type documentation that walks you through the process. Instead it relies on a collection of blog posts, some written by the core team members, but it still feels a little disjointed. There are also a couple of missing elements that I wish it included. I talked about these a bit back in the choosing a library module, but to recap the biggie here, there's no support for maybe. Sure, you can kind of work around it, but the benefits of maybe are just so strong that I wish Ramda included it instead of pointing you to Sanctuary. There was an implementation in the Ramda fantasy project, but it's since been abandoned. I keep thinking I'll submit a PR in my spare time, but I never quite seem to get around to it. The Ramda documentation itself is available at ramdajs.com/docs/. There's a couple of cool things I want to point out, so let's jump over and take a quick look before we start digging into our common operations. If you browse to ramdajs.com/docs/, this is what you're going to see. This is the Ramda API documentation. You can see on the left-hand side there's a list of all of the different functions available, and you can type in and filter if you wanted to look for something. And go in and take a look at that particular function. The other thing I like about the documentation is that it has a REPL available for you to examine each individual function. So I can choose, for example, looking at the add function, I can run it here, and it's going to use RunKit to show me the output, so the output is 17. Or if I want to go in and take a look at that in a way that I can go through and edit it, I can open it in the REPL. And that's going to evaluate that code and show me the output. And this a live dev environment, so if I wanted to change something, I can go ahead and do that. And you can see that things get changed over in the output window. So this is a really nice way as you're going through and taking a look at the documentation to be able to bring it up in a live dev environment and play around with it to start to get a feel for how the different functions work. Getting Started and Common Operations Before looking at the common operations for Ramda, we need to get it installed and configured in our environment. Fortunately, that's really easy. Install with yarn or npm. In Node set it up for a require or in a browser environment a simple script tag. And then you're all set to go, including IntelliSense. If you're using TypeScript or Flow, there are typings files available, too. Real quick, the other nice thing to know about Ramda is that it has a decent ecosystem. Whether that's in the form of separate projects like Ramda-adjunct, a collection of sample functions using Ramda in the Ramda Cookbook, the type definitions I just mentioned, or a nice documentation page that tries to guide you to the appropriate Ramda function, essentially grouping them by functional area. We're going to take a look at those functional areas, there's about a half a dozen of them, and the 200 functions in Ramda can be broken down and slotted into those different categories. Over the course of the next few demos, we're going to take a look at the examples from each of the buckets, but we're going to focus mostly on the top three, lists, objects, and logic. We'll see examples from the bottom ones, but again, the focus is mostly on the top three. Okay, now we can dive in and start looking at Ramda in action. Let's go! Filtering Data Over in our demo environment, you can see I've got a file set up for Ramda here. And at the top I'm just requiring Ramda into a constant r. I'm pulling in all of the people, data, that we're going to be working with throughout all of these demos. It's just a simple JSON file with some sample demo information that we've generated for our application that my company is building, and you can see it's just information about people. We have a couple of regions set up just to clear the console in between runs and set up our output variable, and then at the end here just to log out whatever the value of that output variable is. So all the code that we're going to be writing is going to get dropped right in the middle here, and all it's going to do is write out to our console whatever we've put into that output variable. So let's go ahead and drop our first code sample in. In this case, we're just setting up some basic generic filters, filterEq and filterNEq. We're making use of the Ramda filter, as well as the propEq to go and grab values and filter on values that are passed in. So we pass in a propName and a propVal to the filterEq and it's going to give us back a curried function that all we have to do at the end is pass in the dataset that we want to filter across, and it will give us back any of the items out of that dataset where our property equaled the value that we specified. Slightly different for the not equals, we have that R.complement thrown in and that's going to flip the results of whatever function is passed into it. So in this case, it gives us the not equals where propName is not equal to propVal. Otherwise, propEq and propNEq are essentially the same. We have a quick little example of using that, and you see we need to pass in a couple of different things. We pass in our properly name married, we pass in a value of true, and filterEq gives us back a function that we then just need to pass in our dataset to. Now, we could include that dataset inside the filterEq call if we wanted to. We'd have to tweak a couple of things to make that work, but the idea behind currying is that we want to get to the point where we have these generic reusable functions. So that's what we're going to be building as we go through the demos in this section. So here we pass in people to the function that gets returned from filterEq, and if I set up node I'm going to use nodemon to keep restarting node as things chance. You can see we're starting with our no value, that's what was set up as the initial value of Alt. But if we come over and just save this, it's going to give us all of the people who are married, give us all of their records. So you can see everybody who comes out has a married value of true. That was 6 out of our 10 records. Next we're going to add some more specific filters. Filtering, part Deux (Curried Functions) So here we set up a couple of filters that use the filterEq and one at the end there uses the filterNEq. And you can see in this case we're passing in the property and the value that we want to filter on. We haven't passed in our dataset, so these are going to give us functions back that all we need to do is pass in the dataset and we'll get the filter that's been applied to that dataset. So in my example down at the bottom here, I'm passing in people, which is my dataset, to the married function, which I set up as filterEq with a property name of married and a property value of true. So if I go ahead and save this, nodemon's going to re-run, and I get my married true, the same six that I saw before. But now what if I want to flip that and say I want to take a look at unmarried people? Probably go ahead and save it, and now I get just the four records that represent unmarried people. Same thing if I wanted to take a look at just the women, save that, I get five women. I want to take a look at people who do not have a DNA test. And I get the five people without a DNA test. So you can see we're starting to build these, starting with the very generic function, and then we're building functions off of that that all we need to do is pass in some properties to, and we'll be able to start building out reusable, small, kind of very specific functions that we can pass any dataset into and get back a filtered result based on whatever filter function we're using, married, unmarried, women, men, etc. Sorting Data (and More Currying) Adding in some sorts, you can see we've just defined a couple of generic sort functions here, sortByProp and sortByPropDesc. Each one just takes a property name, uses the R.sortby and R.prop where we pass in the property name that we want to sort by. Our .prop will then give us the value out of that property name, and our .sortBy will sort by that property. In the first case, it does ascending. In the second case, we want to do descending, so we need to use compose, which we haven't looked at a demo of that yet, that'll be coming up in a moment. But basically this just gives us the ability to stitch together different functions that we've created. So we still have the R.sortBy, R.prop, et cetera, that we had in sortByProp, but then we have R.reverse, and R.reverse is going to flip that order. So that's going to give us the descending. So if I wanted to sort people by whether or not they're married, I can do sortByProp and just pass in the name of the property I want to sort on, married, and then I pass in my dataset. Go ahead and save that. It's going to give me all 10 of my people, but we're starting with married true down at the bottom here, and then if I scroll up to the top, we start to get into all of the not married or the married false. If I wanted to change this and flip that order, just go ahead and do that, and you can see down at the bottom here I'm getting married false, and now married true is up at the top. So you can start to see how we're building these very small, very specific functions that allow us to start to build functionality by stitching them together. That's one of the benefits of using composition and functional programming is this focus on very specific small units of functionality that you then build or tie together. Composing Functions Although we saw a quick look at compose in the sort, let's go and add in an actual compose example now. So compose is going to evaluate from right to left, and I didn't mention that before, but I kind of touched upon it in the way I walked through the demo. So here we're going to use R.compose, but we're going to in the first case for marriedByAge, the first thing we do is actually the married at the end there. Compose is going to evaluate our functions from the right side back to the left. So it goes through and it applies the married function, and then it's going to apply the sortByPropDesc age and married by age is then going to give us obviously all of the married people sorted by their age descending. Similar type of thing for menWithDnaTest, it's going to apply the withDnaTest first, and then once that filter is done and has been applied, it will then call the men function and pass in the result from withDnaTest into the men function, and we'll get just men who have DNA tests. Now kind of taking it one step further, we're composing a number of different functions where we're getting married men with DNA tests by age. So again, compose starts at the end, it applies the men filter, then married, then withDnaTest, and then sorts by property age. So that's what we're going to take a look at, if I go and save this, we get the two men who are married, those that have DNA tests sorted by age. If I wanted to flip this, I go ahead and do that. If I wanted to change this to withoutDnaTest, this, let's see, I have just one, so the sorting doesn't really do anything here, I have one married man that does not have a DNA test. So this is composing a number of different functions together to get results out of our dataset that apply to all of the filters that were applied. Piping Functions If having compose work from right to left seems a little offputting to you, then we can go in and instead use pipe. Pipe is the same as compose, except that it works left to right. So here we're getting the same thing, marriedMenWithDnaTestByAge, that's number 2, and we're using pipe. And you'll notice here that our arguments are flipped. Exactly the same as what we had before, but we do men first and then married and then withDnaTest, and then we sort by age. So the results are just like what we saw before. The only difference is that we're evaluating left to right for pipe instead of right to left for compose. Retrieving Top-Level Property Values and Defaults When we're working with our datasets, sometimes we're going to end up with objects that don't have a particular value. So, what's going to happen? We've seen this already where we're using Ramda to go in and get items and just pulling them out of our dataset. Here we're just using R.map to go and get a list of all birthplaces. Now, some people don't have birth places listed in our data. So you can see the second item there we have undefined. You can also notice down at the bottom Chicago is listed twice, we had two people who are born in Chicago. Well, we want to clean that up a little bit. We want to make it unique, we want to get rid of the undefined and put in something perhaps that's a little more user friendly, so how are we going to go and do that, because by default, we're just going to get back whatever the value of that property is, which includes undefined. So let's go in and take a look at a different example where we're using a function out of Ramda called propOr. This gives us the ability to grab a value, but if it's undefined, then we're going to be able to replace it with a default value. So here instead of undefined, we're going to get this not specified. So you can see it's just a little more user friendly, the undefined for user, A, it's not a string, so it may be harder for us to work with if we're trying to put it into the UI, and B, the user is not necessarily going to know what undefined is. So here we can specify a default where if a property isn't given a value, we can use R.propOr to specify a default in that case. Retrieving Nested Property Values and Defaults Similarly, if we're working with objects and we try to get something out of an object property that's nested, we're going to run into a problem with undefined. If we go in here and first try to get a value out of family.motherId, well, if motherId is sitting on family, we're fine, but if family isn't defined, we're going to get an error. So if I go ahead and run this, you can see we've got the type error, cannot read property 'motherId' of undefined, and that's because some of my people don't have a family property with a motherId off, they don't have a family property at all, so it's going to throw an error. So instead what we can do, let me comment this out, and uncomment these, we can use a function out of Ramda called path where we pass in an array of strings that is the path down to whatever property we're trying to get. And Ramda will handle the undefined, if one of those values isn't defined, it won't try to continue on and get to the properties that are further down in that path. So if family is defined, great, it'll go get motherId. If family is not defined on an instance in our data, then it's not going to go on and try to get motherId, so we won't get an undefined error. You'll see we do get a list of undefines here, but that's better than an error. We can take this one step further and use pathOr that like we saw with propOr is going to give us the ability to specify a more user-friendly value. So, same type of idea, but we're using pathOr instead of just path. We still specify the array of strings that give us the properties walking down to the one that we're interested in. If I go ahead and save this, you can see I still get the same value, 1, 3, 7, 9, but then I get not specified for anything that doesn't have a family and therefore doesn't have a motherId. Unique Values Finally, we're going to tie a lot of what we've seen using Ramda together going back to the birthplaces data point, so pull out a list of birthplaces that we could present in the UI that are much easier for a user to work with. So the first thing we're going to do is we're going to get rid of any duplicates. We have this function set up, uniquePlaces. It's going to use the Ramda compose. First it's going to get allBirthplacesOrDefault, so that was the function we set up up here to take out any undefines and replace it with not specified. Then it's going to pass that because we're using compose, it works right to left, so we go from allBirthplacesOrDefault, passes that into the unique function of Ramda, and gives us back then just a unique list of places. Next we set up just a filter not using Ramda, just using a regular arrow function that's going to give us back a Boolean, whether or not val is equal to not specified, and we're going to use that in the Ramda filter in just a moment. So then we set up our places list, again, using compose, so we start at the end. We're going to use uniquePlaces. Then we're going to take the results from uniquePlaces and pass that into R.filter using that isSpecified that's going to give us back a Boolean. So if it's equal to not specified, it's going to get dropped out at this point. So R.sort is then going to get just the birthplaces, unique birthplaces, that have a specified value. And sort here, we're not using our sorts that we set up earlier because those were set to work on objects, and at this point all we have is a string. We just have a list of strings, so we're just going to sort whether or not A is greater than B, and that's going to give us back a list of sorted birthplaces. So if I go ahead and save this, you can see I get my birthplaces sorted. Now just to show you what things look like at each step of the way, let me just go and take some of these out, and we start with our unsorted list of just the uniquePlaces, so the duplicate Chicago has been dropped, but we still have not specified in there. So let's take out just the sort, and now we get rid of both Chicago the duplicate and the not specified, but we haven't sorted anything. So we'll put in the sort back in, and that gets us back to our fully user ready list of birthplaces. Might present this in a pick list or something similar where they can see the list of places where people have been born sorted alphabetically without any duplicates, without any undefines or not specified. So that shows you how we can kind of tie together all these little, very specific functions, into something that gives us really a lot of expressive power to build what we need by stitching those functions together. And that gets us to the end of our look at some of the capabilities of Ramda. As I said in the slides, there's over 200 functions in this library. We took a look at maybe a dozen of them. So we barely scratched the surface. But it should be enough to give you an idea of what Ramda is all about and how it works to build these small, reusable functions. I highly encourage you to go take a look at Ramda if this seems like something that fits well with your approach to programming. I think it's a very well thought out library, and I think it's got a lot of really useful capabilities built into it. Folktale Library Overview Now let's take a look at a library called Folktale. Folktale is a library published by a developer from Brazil and a smallish community of supporters. As with all the libraries we're covering, we're going to begin with a little introductory material in slides and then jump over and take a look at some demos of common operations. This is how Folktale builds itself. A standard library for functional programming in JavaScript, and yes, the bunnies are the logo. The lead developer of Folktale is also an artist, which is kind of cool, and the art's pretty good. Information on Folktale is available at folktale.origamitower.com, which is important to remember because if you do a search for Folktale and JavaScript or try to go right to folktalejs.org, which is kind of logical and does show up in the search results, you're going to end up seeing a page that looks something like this on the left here. At least you do at the time of this recording in early 2018. I'll be honest, I'm not entirely sure what this is as I've never clicked through. I don't get a nice warm fuzzy feeling from something that out of the blue tells me it's going to make my browsing safer, so whatever this is, I don't think it has anything to do with the Folktale we're looking for. Again, the proper URL is Folktale.OrigamiTower.com. Starting with the strengths of Folktale, its documentation is quite good. The documentation is a lot of written more like a series of blog posts, much easier than some of the other libraries for getting started. Of course it helps that Folktale is much less broad, but it's a really good start. The real power of Folktale I think is its implementation of maybe, result, and validation. We haven't touched on these yet, so don't worry if you're not sure what they are. They're going to be the focus of our demos in just a bit, so you'll see them in action. The last strength of Folktale is a little bit dampened by that asterisk at the end there, but I still count the library's fantasy-land support as a solid plus. The asterisk is there to indicate that the Fantasy-Land support is still listed as experimental, so not quite ready for prime-time, but it's a great start. And now a couple weaknesses of the library. I'm a little torn on this, because I don' think that every library should try to include all functionality. Focus and specialization are good. I ended up listing that as a weakness, though, just because I wish that Folktale had a little bit more to it. Now to be fair, a fair amount of library is still listed as experimental in the current release. So once a couple of those aspects of the library are ready for production use, I think both of these weaknesses will likely go away and we'll have a nice, focused library for functional programming. I'm going to be watching this library with interest as we go forward to see where it goes and how quickly it can lose some of the experimental labels. Getting Started and Common Operations Getting Folktale installed and ready to go is pretty standard. There are some additional instructions for using Webpack, Browserify, and more on the website, but the basic setup is a typical include the package, require the pieces, and start coding. Folktale is broken out into nine distinct areas, which makes you think that there's a lot more to the library than there really is. The fact is, though, that a lot of these areas are pretty small or entirely experimental. We're going to focus on maybe, result, and validation. Concurrency, FantasyLand, and data modeling are still experimental. Core/Lambda, Core/Object, and Conversions are partially experimental, or fairly sparse. Again, once the experimental label starts going away, this is going to be more compelling, but for now the maybe, result, and validation implementations are outstanding in making our code more composable. For each of these we're going to take a look at some slides, and then we're going to jump into some demos. So Call Me Maybe Think of a maybe as a box. It contains either the value being returned from the function, or nothing. You can think of the just as success and the nothing as failure. By using a maybe you can be sure that your function always returns something, never null or undefined. The calling or chained code can then open the maybe, the box, check what's inside, and react accordingly, depending on success or failure. As long as your code is maybe aware, everything is going to be good. Not that your code will never fail, but just that when it does, it returns the nothing portion of a maybe and can be handled appropriately. At a certain level, this is really just a semantic difference between doing a bunch of null or undefined checks, but it forces a little bit of discipline and also standardizes things for the rare occasion when you return an undefined from a function as a legitimate value. In other words, there's nothing wrong with returning a maybe just wrapped around undefined. Again, the benefit of a maybe is that it makes our code composable. Continuing the analogy of a maybe being a box, we need some way to unpack it to see what it contains. There's a couple ways to do this and they give us some capability to act on either the just, the nothing, or in some cases, both. The first function to be aware of is map. Map runs on the maybe when it contains a just. If the maybe contains a nothing, the map isn't run. The return value from the map function replaces the value inside the just, so it gives you the ability to work with and modify the return value of a function. This means if your map function returns another maybe that it will be nested inside the original maybe, which is probably not what you want. In that case, what you probably want is chain. Chain is like map in that it only runs on a just. The difference is that its return value replaces the entire original maybe, so you won't end up with nested maybes. The opposite of map is the orElse function. OrElse runs on the nothing value. It's skipped entirely if the maybe contains a just. OrElse gives you the ability to run a code on a nothing. Contrast this with the getOrElse, which lets you just specify a default value. It returns the value from the maybe if it contains a just, or the specified default if the maybe contains a nothing. The last function to be aware of is matchWith. This one's like a switch statement. It allows you to take action on either just or nothing. This slide's been a little dry, lots of terminology without any action, so let's go take a look at the demo that'll help solidify these things in your head and show the real value of maybe. Taking a look at the Folktale maybe and seeing our Folktale.js, we're just requiring Folktale, we're requiring our people data, same data we're using for all of our demos, it's just an extra act of sample data from my company's application, so it's just information about people. We're going to start up Node using nodemon. That will re-run Node anytime there's a change in any of our files. We're going to start by bringing in a little snippet of code here. There's actually a fair amount going on in this, so let me collapse a couple of these to get them out of our way for the moment, and we'll come back to them. So the first thing that we have is our findFirst function. That's going to return either a maybe or a nothing. The first thing it does is it takes the list that's passed in and a predicate function and just uses a standard array find from JavaScript from the JavaScript array prototype to find the first item that satisfies that predicate. If we get anything, it's going to return the value wrapped inside of a just. If nothing came back from that find, then it's going to return nothing. We then have a function called getAllGivenNames, again, returns either a just or a nothing. Goes against the item that gets passed in, grabs the givenNames property, if there's anything there it wraps it in a just and returns that; otherwise, it returns the nothing. GetSecondGivenName, same idea. Checks to see whether or not the item passed in, has more than one item in it. If it does, then it takes the second item in the list at index 1, wraps it in a just, and returns it. If item.length is not greater than 1, then it's going to return nothing. So that's a lot of just kind of prep work, kind of getting things set up for us. Things start to get interesting when we get into our getPersonMiddleName function. You can see this initially just calls findFirst, passes in our data, whatever's passed to it, and then a function. So, taking a look down here we can see when we call it we pass in people, which is our collection of people information, and then just a function that's going to grab the first person with a surname of Dutton and a gender of female. So if I go and save this and nodemon runs, you can see I get over in the right-hand console there, I get a maybe.just with the entire property, or the entire object as the value. So I get Katherine Mary Dutton, age 19, birthplace Chicago, et cetera. Now if I want to start layering in some of the pieces that we have to find above, I can uncomment some of this. Now we're going to call getAllGivenNames, and you can see we still get a just back, but the value is just the given name field, just the property values for given name. We can chain in the getSecondGivenName. That's going to whittle us down even further. We get back just with the value set to just the person's middle name. Now if we want to extract that and actually get into the just the value itself, let's uncomment our matchWith, and you can see here we're saying if it matches with just, then we're just going to grab the value; otherwise, if we get a nothing back, then it's going to log out to the console, no middle name was found, and it's going to return a value just an empty string. So if I go ahead and save this, I get just the middle name, because there was a match for it. If I come down and change my predicate function to something that doesn't exist in the database, then I'm going to get the no middle name found and my variable out has the value of an empty string. So you can see that even though this returned a nothing all the way back up at findFirst, all the rest of these didn't throw any errors. And chain didn't execute because it only executes on success, and matchWith failed against the nothing. So chain is going to work against just, matchWith works against either just or nothing. So that's looking at how we can take a maybe, wrap it around a value, depending on whether or not we've successfully retrieved what we need or not, and return either the just or the nothing portion of the maybe. And then how we can unwrap that to get to the actual value that's inside there, but still have all the composability provided by the maybe. We don't have to worry about things failing, as long as our code is maybe aware. Result The next element we're going to take a look at is result. You can think of result as a replacement for if else statements. It's essentially the same as a maybe with result.ok in place of just, and result.error in place of nothing. So map, chain, orElse, getOrElse, and matchWith are the same as what we covered for the maybe. But result also includes two new capabilities, merge, which lets you simply ignore whether the result contains an ok or an error, and just grab whatever value is returned, and a mapError, which is analogous to map. It allows you to run a function on the error and have the return value from that error replace the value originally wrapped inside the error. Like map, you need to be aware of the possibility of nested results when using mapError. Let's go take a look at using a result in some code. The Folktale result is an interesting little construct because it gives us the ability to essentially replace an if/then structure with something that's more composable. Taking a look at our code here, for this particular example, I'm not actually using the people.json because I wanted to come up with an example that showed how we can continue executing, even when things fail. Or make it all the way through if everything works successfully. So, a little bit of a stilted demo here, but still I think gets the idea of the result across. So we have a function at the top appropriately called mayFail, generates a random number, and 9 times out of 10 it's going to return the ok. One time out of 10 it's going to fail. So when it returns okay, it says, made all, iterations successfully. If it fails, then it's going to tell us which iteration it failed on. Now when I come down here and take a look at the call, we have out = mayFail, so that calls it the first time, and then we have a series of chain functions that call mayFail again. So we call that function repeatedly; essentially I'm waiting for it to fail. Or get all the way through and succeed ok. Now remember that the chain is only going to execute on an ok result. So once we hit that first failure, it's going to skip down to the matchWith. So let's go ahead and save this. In this case, it failed on iteration 2. I'll just continue saving until we see, there we go, so it made it through all five iterations successfully. So the first time through on line 17 it made that call and succeeded, and then because that one succeeded, it called the first chain on line 18, and that one failed. So at that point, we had a result.error coming back from our mayFail, so the chain on 19, 20, and 21 don't execute, and we skip right down to the matchWith and we have our error. You can see if I refresh this, again, it failed on the second iteration. Let's see if I can get it to the point where it, there we go, all five iterations. This time it hit the first call to mayFail on 17,; 18, 19, 20, and 21 each execute because each one before it returned a success, and then the matchWith on line 22 executed and we had an ok that had come back from the mayFail on 21, so we get our value back, and the value in this case has made it through all 5 iterations successfully. So as I said before, that gives us the ability to replace a noncomposable if else with a much more composable structure. We can continue to tie these together knowing that it's going to be okay whether our calls succeed and return an ok or fail and return an error. Validation The last piece we're going to look at from Folktale is validation. Validation is very similar to result, except that result is a gatekeeper. When something fails using result, you immediately get moved down the failure path. Validation, on the other hand, is a collector. It collects all of the failures and allows you to react to them collectively. We'll see this in just a moment when we get to the demo, but first let's take a look at some of the functions available. Map, the same as what we've seen before and still success only. MapFailure, also still the same and failure only. MatchWith, both success and failure, same as what we saw already. And now the two that are unique to validation, first concat. Concat lets you combine validation, success, or failure. When combining failures, both are included in the final result. Combining two successes, you get just the final one included. Combining a success and a failure, only the failure is included. And last, collect. When you've defined multiple validation functions, collect allows you to combine all of the results into a single set. Now collecting concat might seem a little confusing, so let's go take a look at these in the demo and we'll get a better understanding of how they work. Taking a look at Folktale's validation, we're going to do this in three different snippets because there's a fair amount of code to run through this. Starting with setting up some of our validation functions, we're going to be checking for minimum length and no spaces. So min length first takes in a field name minLen and a value, and if the value passed in is greater than the minimum length, then we're going to return a validation.success and just return the value. If that validation fails, if value doesn't have a length, it's less than the minimum length or equal to the minimum length, then we're going to return a validation failure with a message of whatever the field name is, must be longer than whatever number of characters. So either success or failure gets returned from our validation function. No spaces is a little simpler, we take in the name of the field and value, we check to see whether or not the value contains a space. If it does not, then we return a success and just return the value. If it does contain a space, then we return a failure with the message their fieldName cannot contain a space. So that's setting up the functions that actually do the validation itself. Now we'll build up some validator-type functions, clean these up a little bit here. We start by checking if the password is valid. It's going to receive a password. And then we call into Folktale's validation capabilities. We start with a success, because remember, I said before that when you're combining validations, if you have a success and you add another success to it, the first success gets thrown away and only the second success gets passed along. If you have a success and you add on a failure, then the success gets thrown away and the failure gets carried along. If you have a failure and you add another failure or concatenate another failure onto it, then both failures get passed along. So we start from a success, we can concatenate onto that, the result of our call to noSpaces for the password. So that's going to come back as either a success or a failure. Regardless of what comes back, we concatenate onto the end of that, our call to minLength where we check the password. So that's going to determine whether or not password valid is going to be a success or a failure. Same type of thing for checking if the name is valid, we start from a success, concatenate onto it whatever the result of our noSpaces check is. So now we can go into the next snippet where we actually go and set the value of our out variable, which is what gets written onto the screen. We start by calling validation.collect, and this is going to allow us to get all of the results from passwordValid and nameValid, both of those checks, the results will be combined, and given back to us as one collection. So if I go ahead and run this, by saving, you can see we get back a success. And the value that gets displayed is in this case just the username. But if I go and change this, say, by putting a space into our password, you can see now I get back a failure that says the password can't contain a space. Well, now let me start putting multiple failures in where we have a space, let's do this. Now all of our validation fails, so we get back an array with three strings in it. Password failed on two cases and the name failed on one. Well, it's not very useful, you can't do much when you have everything wrapped up inside that failure, so let's see what things would look like when we uncomment this matchWith. So now we get a failure message and the valid is each of the strings that was returned as part of our failure. So if I start making things valid again, you can see the strings start to disappear. We're down to just one message, and now if I take the space out, then we'll go to success. So that gives us the ability to collect successes and failures as we go through and then deal with the collection of all of the results at the end. And that's the power of working with the validation. Very similar to the result, but like I said in the slides, the result is more of a gatekeeper. As soon as something fails with the result, you go down the failure path. Whereas with a validation, you continue to check your different conditions until you get to the end and work with everything at the end. So that wraps up our look at Folktale. We looked specifically at the maybe, the result, and the validation. There are other aspects to this library. A lot of them are still marked as experimental, so I didn't cover them because I wouldn't recommend them for production use, but this is one to keep your eye on. There's a lot of good things that I think are going to be coming out of this library in the not-too-distant future. FKit Library Overview The next library we're going to take a look at is called FKit. It was created by a developer from Australia originally back in 2014. It seems to have gone dormant for awhile, but then reactivated late in 2017 and appears to be continuing to be active in 2018, which is good because it's an interesting little library with some pretty nice capabilities. As with all of the other libraries we're looking at, I'm going to try and keep the slide portion short, just covering a basic overview, and then get over into the demos so you can see the library in use. FKit is a collection of about 130 utility functions. In some ways it's a little outdated with the introduction of some capabilities in ES6, but it still has a good amount of useful stuff. One thing I like about it, though it takes a little getting used to, is that it treats both strings and arrays as lists. An array is a list of elements and a string is a list of characters. This is nice for string manipulation, but it's where ES6 stepped in and took over some of what FKit offered in terms of array manipulation. Nonetheless, FKit still has a little play as it provides some immutability and composability, which ES6 doesn't directly give us. More information on FKit is available at the URL shown here. From a strengths point of view, FKit packs a lot of power into a small footprint. Those 130ish functions I mentioned are all provided in about 3K when minified and gzipped. Now, compactness isn't a huge deal these days, but it's still nice. In addition, the composability provided by the FKit functions is easy to grok and work with. And finally, once you get over a little learning curve, treating strings as lists of characters is a nice capability when you need it. From the weaknesses side, my biggest concern is the bite ES6 took out of some of the bang provided by FKit. I'm hoping that the flurry of activity recently will update the library for the latest changes in JavaScript. Finally, and realizing that I have high standards in this area, the documentation for FKit needs some attention. This isn't anything unique to this library, but simple API documentation with minimalistic examples isn't sufficient in my estimation. Not a huge deal, but it would go a long way to helping a library gain traction if it had really out-of-this-world documentation. Getting Started and Common Operations There's nothing special about getting moving with FKit. You get the bits with Yarn or NPM, require the library, and start writing code. FKit is loosely divided up into six sections of functionality. Functions, mostly revolving around composing and currying functions and working with parameters. We're going to be looking at compose in the demos. Lists. We're going to spend a lot of our time in the demos working with lists. Logic. The standard Boolean operators you would expect, plus some interesting capabilities for branching and also implementation for a where all and where any to check for conditions where all or any parameters satisfy a criteria. Math. As you would expect, typical arithmetic operators and comparisons, but also other functions for dealing with numbers and collections of numbers. Objects. Functions to work with objects, properties, and the like. We'll see some of these in the demos, too. And last, string. Now this isn't the interesting string capabilities I mentioned before. I'll be honest, I'm not exactly sure what this group is for. All it contains is three functions, replace, two upper, and two lower. Looking at the source code, the replace function is curry, which is nice, but the two lower and two upper just call their plain JavaScript equivalent, so they're a little odd. Anyway, let's go take a look at FKit in demos. Filtering Over in Visual Studio Code, we have our fkit.js file open. We start by requiring FKit into a constant F. Then we get our data by requiring the people.json file. We've used this in other demos as well, it's just a collection of information, demo information, exported from our application. It just has information about people, but it's a nice collection of a little more real world data that we can work with. Inside our supporting regions here, we're just setting it up to give us some space, some white space in the console, and then set up our output variable. Below that we simply log out the output and some information about how many records we found, and again, give us a little bit of space. Code that we're going to write is going to go right in the middle here. Taking a look at our first snippet for FKit, we're going to set up some filters, so we have a filterEq and a filterNEq, equal and not equal. We're using FKit's curry function. It takes a function that expects three variables and passes that into FKit's filter. We then make use of FKit's compose, which we're going to take a look at a little bit later to get the property name using the function f.get, pass in the property name that we're looking for, and compare that to F.eq with the property value that was passed in. So compose ties those two together and causes the value of the get to be passed in to be used as the item to be compared with F.eq. And then we have our data at the end, which is the people data that we're going to be using as our dataset. Similar for filterNEq, except that instead of F.eq on line 12, we're using F.NEq to get the opposite. So we could set this up as a simple call on line 15, storing it in our out variable. FilterEq we're going to get everybody from the people collection who have a value of married set to true. We'll go ahead and save this and startup node with nodemon. We see the output is just all the married people, so the six records from our dataset where married is set to true. Filtering, part 2 and Partial Application In our next clip, we're going to go and set up some filters building on the equals and not equals filters that we had set up. And here we're using some partial application to only pass in two of the parameters. So in conjunction with the F.curry that we have up on lines 8 and 11, this is going to allow us to wait until we're ready to pass in the data, and then the function will actually execute. So we have married looking for a value married is true, unmarried, filterNEq married to true, women, men withoutDnaTest and withDnaTest, all specifying the property name and the value that we want to use for our filter. So you can see we have our example down here, withDnaTest is going to give me everybody from the people dataset that has a DNA test. If I go ahead and save that, nodemon's going to rerun things for me, and you can see I have the five people from my dataset that have a value in their dnaTestId field. Sorting Next up we're going to add some sorting capabilities. You can see here we have a pretty standard sort function beginning on line 28 running through line 34, just comparing the whatever property name we pass in, comparing the a and b, returning 1, 0, or -1, depending on those values. So pretty basic sort function passed into FKit's sortBy. Same type of thing for sortByPropDesc, except that we've flipped our 1 and our -1, so we'll sort by descending there. If I go ahead and save this, we'll get all 10 of our records, but this time the bottom we have our unmarried people and at the top we have our married people. So it's sorted all the true for married and then all the false for married. Composing Functions As we start to add more and more functions in here, you can see how things work in a functional mode of programming where we're building these tiny little functions that do one thing and then we tie them together to introduce the functionality that we need. And the way that we typically tie those together with FKit is with compose. Much like some of the other libraries we've looked at, compose is used to say take the results of these functions and pass them, basically chain them together. So here we're setting up a married by age using F.compose, and there it's going to first run the married filter, which we had set up above, take the results from the married filter, and pass it into sortByPropDesc and pass in the age property. So it'll sort our married people by age. Same type of thing for men with DNA test, and then kind of a big example, marriedMenWithDnaTestByAge. We're using compose, starts at the end, it says give me all the men, then filter that for men who are married, then filter that for married men with a DNA test, and sort by property age. So if I go and save this, we're going to get our two people who are married men with a DNA test sorted by age. If I flip this, we'll get the same results, but now they're by age descending. So you can see how we have these pretty generic functions at the beginning to do generic filtering and then filtering on a particular property, generic sorting based on a passed in property name, and we can tie them together using compose to introduce the functionality we're looking for. And again, compose, the thing you need to remember about that is it starts from the right and works its way to the left. Top-Level Properties Continuing on, we're going to start working with individual properties, so here we're just getting all birthplaces, so each person record has a birthplace property, and we're just generating a list using F.map to apply this function, this arrow function to each of the items that we pass in in people. And that's going to give us back just an array of birthplaces. So when I save, you can see I get a list of the 10 birthplaces. But you'll notice a couple things. First of all, it's not sorted. We have an undefined in there, which means that somebody doesn't have a value for their birthplace, and we also have Chicago listed twice at the end. We've got two people born in Chicago. We might want to clean this up a little bit. So, let's go ahead and take a look at how we can use some other capabilities from FKit to go and clean up this list. Default Values The next snippet we'll put in is going to set up an allBirthPlacesOrDefault function. Now we're going to use allBirthPlaces as the first function that gets executed from our compose. So, F.compose starts at the end, applies the allBirthPlaces filter to give me just that array of birthplace names, and then it uses F.map to go through and look for any place where the value or the birthplace value is undefined. And in that case, it replaces it with not specified. So now we've been able to specify a default value that's going to be a little more user friendly than undefined. The user is not necessarily going to know what an undefined is. So if we go ahead and save this, you can see that now we have not specified instead of undefined. So this has given us the ability to, like I said, specify that default when we need to. We still have a little work to do on this list, so let's go ahead and take a look at how we can make everything in the list unique. We'll get rid of one of the two Chicagos. Unique Values So the next snippet we're going to take a look at is going to give us the ability to get rid of duplicates in our list of birthplaces. We set up a function called uniques, and we're going to use FKit's curry and also a function called nubBy, and if you're curious, that comes from Haskell. And essentially nubBy is going to give us the ability to pass in a comparator function. So it's going to loop through everything in our dataset that gets passed into nubBy and pull out anything where this comparator function returns true. So if a is the item already in the list and we try to add in another item where we're comparing another item b that's the same, b is going to get excluded. So we set up uniquePropVals, again, using curry. We're going to curry a function that takes a function and then a collection of data, and will return to us the value when we apply that uniques function from line 69 to that function and that data. Down on line 72, we call uniquePropVals, we pass in the results that we got from allBirthPlacesOrDefault. On line 73, we're using nothing particular to FKit here, just a basic arrow function to give us anything where the value is not equal to not specified. So anything where that is true is going to be returned to us when we use the F.filter down on line 74. So we take our uniquePlaces as the first function that gets evaluated in our F.compose on line 74, the results of that get passed into our filter, and anything that is specified will remain in the list when the filter is done. We now have a function that we can pass, it's been curried down to the point where we can pass just our dataset into it. We store that in our out, and then that will get written out to the console. I go ahead and save this, and you can see not only did we get rid of not specified, we also get rid of the duplicate Chicago, IL. So an interesting way of tying these functions together getting all of our property values, all of our birthplaces, and then pulling out the duplicates, and then pulling out the ones that have a value of not specified, and returning just the list of those items that have been specified. Nested Object Properties The next thing we're going to take a look at with FKit is how do we handle nested object properties that may or may not exist? So here let me start by actually commenting out this code for just a moment, and putting this code in place. So here basically just to simple map, we're going to iterate over the collection that gets passed in and try to grab all of the mother IDs from the family property inside each item in our dataset. If I go ahead and save that, I get an error, because not every person specified in my people dataset has a family property. And if it doesn't have a family property, I'm going to get that error when I try to get to val.family.motherId. So this is the problem that we're solving here. Let me undo these changes. And now what we're doing is using the getIn function that FKit provides and we pass in an array that is the path to the property we want to get. So, instead of family.motherId, pass an array family and motherId, and we could continue on if there were additional path entries to get down to the item that we're looking for, or the property that we're looking for. We wrap all that up in our map so that it gets applied to every element coming in the dataset, and then we can just go ahead and save, and now you see we're going to get the four instances where we have a value and the six instances where we don't. So that's how we can go through and without having to put in a lot of null or undefined checks, we can get values out of nested properties. Nested Object Default Values The last thing we'll take a look at for FKit is similar to what we had seen earlier working with properties where we want to be able to specify a default value. So this is similar to what we saw in the last clip where we're using getIn and passing in the array of property names to walk through the object to get down to the property that we're looking for, in this case, family.motherId. But we also have inside the compose we put in another F.map that goes through and looks for anything that's not defined, so it's going to get those undefines, and replace them with not specified. So this is another way that we can specify a default if a particular object inside our collection doesn't have nested properties that we require. So I go ahead and save this, and you can see that instead of undefined I've now got the slightly more user friendly not specified. So that gets us to the end of what we're going to demo for FKit. As I said, a nice little library, it's got a lot of nice useful functions. I like the composability, I like the currying that it gives us, using it for filters is very straightforward. So there's a lot of power in this little library; I think it's something you probably ought to take a look at. Sanctuary Library Overview Sanctuary is a library which began life as an extension to another library we've already covered, Ramda. It builds itself as like Ramda, only stricter. You can decide whether that's a good thing, but all in all Sanctuary is an impressive library. As with all of the libraries we're looking at, I'm going to try to keep the slide portion short, just covering a basic overview, and then get over into the demos so you can see the library in use. Sanctuary's tagline is refuse from unsafe JavaScript, which is a bit indicative of its take on the world being more than just functional program, though that certainly its means to the end. The website for the library is sanctuaryjs.org. As I said before, Sanctuary is impressive. Unfortunately, I think it's attempting to boil the ocean. It tries to tackle a whole lot, and while it's still a work in progress, as all good libraries should be, it misses the mark a bit right out of the gate. Let me explain with the strengths and weaknesses comparison I've been using for all of the other libraries. First, the strengths. Sanctuary is I believe the most complete library we're covering, primarily because in addition to its standard functional elements, it also implementations of maybe and either, which give it an edge. Another plus for Sanctuary is the team behind it. Sanctuary is still actively supported and has an extremely helpful group of folks willing to jump in and help. Do you have a question? Join their Gitter chat and you'll have an answer in no time. Which is actually pretty good, because now it's time to discuss some of Sanctuary's weaknesses, and I think the biggest problem the library has is its documentation. There's no other way to describe the documentation for Sanctuary except dense. The documentation is very complete from an API point of view, but it's very hard to read. It assumes a level of knowledge about functional programming that I just don't see a lot of JavaScript developers bringing to the table. My other concern about Sanctuary is its apparent preference for functional purity over ease of use or real-world application. Fully realizing that this is subjective, I still can't help feeling like Sanctuary's syntax and approach are harder when dealing with real-world coding issues because of the strict adherence to functional programming tenets. And last, I'll mention something that's both a strength and a weakness. Sanctuary is very opinionated. On the strength side, it makes the library unambiguous. There aren't many, well, you could do it this way or that way situations in Sanctuary. It has an opinion on how things should be done, which makes for less decisions on the part of the developer. That's generally a good thing. On the negative side, though, this makes the library less flexible. All in all I think Sanctuary is a good library, and for the most part, the weaknesses aren't insurmountable. A simple beginner level getting started type guide would go a long way to helping here. Follow that up with some blog posts are short articles walking through some different common scenarios, and the biggest problem, the documentation, is fixed. Getting Started and Common Operations The initial process of getting started with Sanctuary is pretty typical. Yarn or NPM to get the bits, require the library, and start coding. There's also one other additional step to configure Sanctuary that we'll take a look at in the first demo in just a moment. Sanctuary has a somewhat dizzying number of categories for the functions and capabilities it provides. There's obviously no way we're going to cover all of these in this overview of the library, so we're going to focus on filtering, which Sanctuary has under Fantasy Land, composition, and maybe. We'll also cover that extra configuration step I mentioned, so let's go take a look at the demos. Setting Up the Environment and Filtering Getting started with Sanctuary, there's one additional step that we need to go through that we didn't have to do for any of the other libraries. And we just need to configure our environment. The reason for this is that Sanctuary includes a pretty extensive runtime type checking capability, which is really nice for development, but probably not something you want running in production, because it's just going to take extra cycles, it's just extra overhead at that point, but while you're doing active development, it gives you the ability to get some more detailed error messages, among other things. So when we're setting this up, we start by requiring and env or environment from Sanctuary. We then have our standard require to get our people data; we'll take a look at that in just a second, that's not Sanctuary-specific. And then we call create to set up the Sanctuary environment. And we'd have to pass in two parameters, checkTypes is true, that's going to enable the runtime type checking, so we have that on while we're doing development, and then we set the environment equal to the default environment coming out of Sanctuary. If we're going to go into production, we probably want to change this to false to disable that runtime type checking. Like I said, it's just extra overhead. Once we have that set up, our Sanctuary environment is now initialized and ready to go. Real quickly looking at the rest of what we have going on here, our people file is just a json file with information about made-up people, fictional information. We're going to use that as our dataset for doing our queries. We also have a couple of collapsed regions here, we're giving it some space on the console, we're setting up our out parameter, and we're setting it to no output by default, that's going to be what's written out to the node console. And you can see here is where we write it out, and again, just give us some additional information about the number of records, and then some space to be able to see the results a little more clearly. Once I go over here I'm going to start up node with nodemon, point it at my Sanctuary file, and it's just going to go ahead and run, and I get my default no output. So now we're ready to start putting our snippets in. We'll start with some basic filters as we've done with some of the other libraries. So we set up a filter to filter on a particular property, looking for a particular value. We use the Sanctuary filter function, and essentially just an arrow function that says each item we're going to include it if the propName is equal to the propVal. Similar type of thing for not equal, except we do the item propName not equal to propVal. So that's going to set up a function using the Sanctuary filter that we can then just pass in the information that we want to sort on, so we pass in married, and we're looking for a value of true, but then we also pass in the people or our dataset. So now we're going to get back, if I save this, nodemon will run, and we'll get back the people from our people dataset who are married, who have a married value of true. If we take a look at our next set of functions, or filter functions, we can take that one step further and set up specific targeted functions for individual properties. So we can say give me a function that's going to accept then just the dataset, and it's going to apply a married equals true filter to it using filterEq and hard-coding in married and true. Same thing for married an false to give me unmarried. We can do it on the other properties as well, non-Boolean properties. So we can say give me everything where the gender is equal to female, and that's going to be a function that I'll call women; the opposite for men. Same type of thing for without a DNA test or with a DNA test. For the with a DNA test, we are using the filter not equal to get everything that's not blank. So now if I want to get the married people out of my dataset, I can use that married function, and all I need to pass in is the dataset. Go ahead and save and I get those six records. If I want to get just the men, save it, and I get just the men. So we're starting to build, the same as we've done with some other functions, we're starting to build out these curried functions using some of the capabilities of Sanctuary to allow us to filter our dataset. Sorting Next we'll take a look at doing some sorting. So we'll put a couple of sort functions in. We have sortByProp. It's a function that takes a property name and then it sorts by the collection that's returned from S.prop and we pass in the property name. So S.prop is going to go through all of the items inside the collection that gets passed to it, and it's going to pull out the values for that property name. SortBy is then going to take that collection and sort it. In this case, it'll sort it alphabetically ascending because we don't specify a sort function. Similar for sortByPropDesc, we're going to take a propName, but then we need to do a little additional work, so we need to compose. We're going to take a look at compose a little bit later in more detail, but it's going to allow us to apply multiple functions in sequence. It's going to start on the right-hand side, which is the same as what we saw for sortByProp, so we've got the collection of values out of that property name, sort them, and then it gets passed into S.reverse, which flips the sort order, as you would expect. So that's going to give us sortByPropDesc. If I go ahead and save this for a sortByProp and pass in a value of married, and my dataset of people, I look over here I start on the bottom with my married as true. As I scroll up towards the top of my list, I start to get married as false. So they're sorted by that married value. If I wanted to see this go the other way, go ahead and save it, I get the same 10 records, but now I have married false at the bottom and married true up top. Composing Functions Moving on, we'll take a look at Sanctuary's compose capabilities, starting with the actual compose function. Now things are a little bit different than what we had seen in, for example, Ramda's compose function. When we're composing with Sanctuary, it takes two parameters. So we can compose two functions at a time. So we can set up a marriedByAge where we're composing our married function, again, starting from right and coming to left for compose, so we compose the married function and our sortByPropDesc we pass in the property age. That's going to give us back married people sorted by age descending. We can set up another dual function composing. We can say give me the people with DNA tests and then filter that additionally by passing in the men filter. So it'll first apply the withDnaTest, and then it'll take the results of that and pass it into men and give us then just the men with DNA tests. If we want to move onto doing multiple function composition, we need to nest our compose functions. So marriedMenWithDnaTestByAge we need to do S.compose, and then inside that we do another S.compose, where we put together withDnaTest and marriedByAge and men. So the way this is going to be evaluated is we'll first evaluate the last function in the compose, so men, and then we'll take the results of that and pass that into the initial compose, which will filter for DNA test and then sort married by age. That'll give us married men with DNA tests sorted by age. If I go ahead and save this, we can see that's what we get. We have two married men with DNA tests and they're sorted by age, starting with the oldest and working our way down. Piping Functions Sanctuary's pipe function is going to be similar to compose with two distinct differences. The first is that pipe is going to operate left to right, and the second is that it allows us to pass in an array of functions and it will operate on all of them. So whereas compose was limited to two functions at a time, pipe we can pass in an array of however many we want. So in our example here of marriedMenWithDnaTestByAge2, we're calling S.pipe and passing an array of marriedByAge, withDnaTest, and men. Each of those filters will be applied in that order. So we'll get married and sorted by age, in this case descending, that's the way that function is set up, and then it will take the results of that and pass it into withDnaTest, and then it'll take the results of that and pass it into men, and the output we're going to get is going to be similar to what we saw before, but we did it in without nesting our compose calls. So we have our married men who have DNA tests sorted by age descending. Maybe The last thing we're going to take a look at for Sanctuary is working with their maybe monad. So we'll paste in our code. It's going to be a little bit different from what we saw when we worked with the maybe in Folktale. There we talked about how we were creating a maybe. Here we're going to work with how we get data out of a maybe that Sanctuary provides to us. So we're going to set up a couple of filters. We're going to set up an age filter using the filterEq that we had set up earlier. We're going to use Sanctuary's curry, specifically curry2, to take 2 parameters required by a function and distill it down to just 1 that we can then call and pass in our data. That will give us the first element coming out of our collection of data that matches our filters. We set up an is68 using that curried function first, and we pass in a predicate of isAge using the filter we set up on line 49 and say give me anybody whose age is 68. The function first, defined on line 50, is going to essentially just extract the first element out of the array of people who are 68 years old. We set that up as our out variable. And the last thing we need to do is pass in our people because that's the way we have the currying set up. Is68 people is going to give us the first person from our people list that it encounters who has their age set to 68. So if I go ahead and save this, it's going to give me a just with the nested object inside that is my person. Well, that's great, but I want to get to the actual information. I don't want to work with the just, I want to get the information that was returned from my function. So to do that, I'm going to make use of some additional capabilities in Sanctuary. Specifically I'm going to say I'm going to use the fromMaybe function to open up that just and pull the information out. Specifically what I'm going to be looking for is the surname property. So I use S.prop, the property I want is surname, and it's going to get it from ultimately is68, passing in my people dataset, but the fromMaybe is going to pull the person object out of that just and allow me to work with that. Because if I tried it without the S.fromMaybe, then S.prop wouldn't be able to get at the data inside the just. I would get an error that said that the object doesn't have a surname property, because just doesn't have a surname. It's the user object that's inside my just that has a surname property. Now fromMaybe also gives me the ability to specify a default. So if there is no surname on whatever comes out of my is68, then I'm going to get a surname of none. If I go ahead and save this, I'm just going to get that one record. This can be the first person who had an age of 68, just their surname. So that's working with the maybe from a slightly different angle than we had seen previously. Setting up a maybe would be similar to what we saw in Folktale, but this gives us an idea of going in and pulling the information out to be able to work with the actual information once that maybe has been unwrapped. So that's a look at working with some of the capabilities of the Sanctuary library. There's a lot of capabilities in Sanctuary. If this peaks your interest, I would say it's worth your time to go ahead and start to dig into it. If you're looking for more information on Sanctuary, the portion in the slides gave you the URL to go and start looking at their documentation, which does include a REPL, so you can actually do some of the coding live right in their website; you don't need to necessarily set up your whole separate environment if you just want to kick the tires a little bit. Monet.js Library Overview The last library we're going to take a look at is called Monet. It doesn't appear to be quite as popular as some of the others, but it's still an interesting library with some good stuff. As with all of the rest, we're going to get through a quick overview of the library and then jump over and take a look at some examples in code so you can see the library in action. Monet builds itself as powerful abstractions for JavaScript, but it's also a little bit telling that it also labels itself as for people who wish they didn't have to program in JavaScript. It's a little bit of the author's bias showing. Nonetheless, it's a library worth looking at. Additional information is available at the URL shown here. Looking at the strengths and weaknesses of Monet starting with the strengths. For a relatively small library, Monet has some interesting aspects that make it pretty broad. We'll see this more when we take a look at coding with Monet in just a bit. I also like its implementation of immutable data structures. I found them pretty easy to work with, and also the non-empty list was an interesting addition. We'll see these in the demos as well. Now, the weaknesses. Like every other library we're covering, the documentation is weak, primarily just an API list with some lightweight examples. Another issue is that some of the functionality is only available in what amounts to an extension library of object and function prototype modifications that they call monet.pimp, which doesn't support node and has an uncertain future from what I can ascertain. It's not a huge deal from a functionality point of view, but the documentation has a slight bias towards the pimped functions, which is going to make things a little harder for folks just using node and not a browser. One last weakness to mention, and I moved this all the way down to the bottom of the slide because it's not something I can really put my finger on, but I just can't get a good feeling on the future of Monet. With other libraries, I could tell that they were either underactive development to fix issues or extend the functionality, or else they were essentially done and just in maintenance mode, which was okay if they were essentially complete. I just couldn't get that same sense with Monet. There are still some things I would consider holes, but I can't see that there are plans or activity working to fill them. Again, don't place too much on this, as it's not something I can quantify, just a gut feeling. I just felt that I had to mention it, partly because I like Monet, so it would be a shame to see it die off. Getting Started and Common Operations Getting started with Monet is easy, and really exactly the same as all the other libraries. Yarn or NPM, require, and write code. Nothing fancy, which is really just how it should be. For a somewhat small library when compared to some of the others, Monet packs a lot of functionality. There's really no way I can demo all of this in just a simple overview of the library, but some of this is pretty unique, so I want to spend a little time in slides covering some of the things we're not going to get to in the demos. In the demos, we're going to look at immutable lists and the non-empty lists. So I want to walk through these others, at least enough to make you aware of them. Let's take a look at maybe, either, validation, and the catch-all other categories in slides. Just for completeness, I need to mention that there are three additional monads available in Monet that we're not going to be looking at. Reader allows you to inject dependencies into your pipelined functions. Free allows you to overcome JavaScript's lack of support for proper tail call elimination. Honestly, this isn't really something most people worry about, which is why we're skipping this one. And, IO, which allows you to include functions with side effects in your functional pipelines. If you want to read more about these, you can take a look at the Monet website. Maybe, Either, and Validation First let's take a look at the maybe monad. Conceptually this is exactly like the demos of maybe I did in the module on Folktale, but there are some slight syntactical differences. A maybe is essentially a wrapper around either a value or nothing. The benefit is that you can always return a maybe from any given function and then let the calling code unwrap it and act accordingly, on either the value or the fact that it's a nothing, or in Monet terms, none. In the example here, we're calling a function that returns something or else undefined. Maybe this is a call to retrieve a DOM element, so we can't easily control the return value. From our function, though, we can control the return value. If rv has a value, we wrap it in a Maybe.Some and return it. If rv is undefined, we return a Maybe.None. Whatever receives this return value can be guaranteed to get a maybe back, it just needs to unwrap the maybe to get to the result. A related monad is either. Like the maybe, it will always contain one of two values. This time, though, they're considered right, which is the non-error condition, or left, which is the error condition. Either.Right is the same as Maybe.Some for all intents and purposes, and Result.Left is equivalent to Maybe.None. The difference is that for either left can have a value, typically an error message. Maybe.None can't have a value, it just is. Like maybe, either is conceptually identical, but syntactically different from Folktale. So you can take a look at the Folktale demo clips or on the Monet website if you want to see it in action. In the code here, using the same getSomethingOrUndefined function we mentioned in the previous slide, we're going to return rv if it isn't undefined, or else the error message stating that rv is undefined. This is a composable way to handle errors that you can't readily do with a try catch. Finally, we'll cover the monad-like validation structure. This one is monad-like for some obscure technical reasons that really aren't relevant, but we can lump it in here with our monads anyway. Like Folktale, Monet's validation is going to either contain a success or a collection of failures. It's also similar to either, except that it can contain an accumulated list of failures. So essentially you can chain a bunch of validation tests together. If they all succeed, the resulting validation structure will contain the final success. If any fail, the validation will throw out any successes that had already been recorded and begin accumulating failures. Even if later functions succeed, once there's a failure in the validation, subsequent successes are ignored. Again, you can see conceptually identical examples of this in the Folktale demo, and then look at the syntax on Monet's website. In this quick example on the screen, we start with a success and then apply our validation functions. If both validationFunc1 and validationFunc2 succeed, we'll have a validation.success. If one or both fail, we'll have a validation.fail, containing the information about each failed validation function. Compose, Curry AndThen The other functions part of Monet is where we find the compose method. Compose is like we've seen before, it allows you to combine functions so that the output of one function is passed in as the input for the next function. Other functions also include curry, which allows you to start doing partial application of your functions, and then AndThen function. We've seen the first two of these already. We talked about them in generic terms and then in terms of the libraries that support them, so I'm really just going to go into a little more detail on the last one. Fortunately, it's pretty simple. AndThen is like pipe from Ramda. It evaluates the list of functions that you're trying to compose together, but it does it from left to right instead of what compose does, which is right to left. We saw that with the pipe function in Ramda, and like I said, it's essentially compose, but the order of the operations is flipped. Heads and Tails - Immutable Lists To get started with Monet, the first thing you're going to do is require the library here we stored in a constant M. You could also require the individual pieces if you're not using the whole library. The next thing we're going to do is bring our data in, as with all of the other demos working with this people.json file, just some sample data about people. You can see there's, well, there's 10 people in here and we've got some information on first name, given name, surname, age, et cetera. So it just gives us a little bit more real-world data to work with. We can start to query and work with that information. Back in Monet, we've got a couple of collapsed regions here. You can see we're clearing out the console. We set up an out variable, that's what we're going to end up writing out to the console. For this particular demo, I'm setting up a couple of new people. We'll be looking at inserting those later, so you can see it's just individual records about people that we're going to insert into our Monet collections. Down at the bottom we just have another region that logs out whatever we've put into that out variable, and then gives us a little space on the console. So that's kind of the getting started pieces for this demo. I also wanted to start with a look at how Monet structures their immutable lists, because it's a little bit different from other things that we've seen and it may not be exactly what you expect, and it's important to understand this in order to work with the library. So each list, each immutable list in Monet, is made up of the first element called head, and then everything else in the list, which is the tail. So in our examples here, we have an immutable list that contains the numbers 1, 2, and 3. In the first example, 1 is the head and 2 and 3 are the tail for that first immutable list. But then 2 and 3 are actually separate immutable lists. And you can see I have it kind of broken out where in the second immutable list, 2 is the head and anything below that is the tail. So as you build out an immutable list, what you're really doing is saying I've got the head object and then I've got everything else, which is the tail. And then for the third element in the list, we have 3 as the head and nil as the tail, so that indicates that we've gotten to the end of this overall list. So each list is going to have a head and then either another list, another immutable list, which is the tail, and potentially contains nested immutable lists, or it's going to contain nil, which indicates the end of that immutable list. So we'll be working with some of this as we go through and taking a look at how we work with Monet. Creating Immutable Lists With that out of the way, let's go and create our first immutable list. So there's a couple of different ways we can go about doing this. If we have an existing array, such as our people array that we pulled in from the people.json, we can do the Monet or M.List.fromArray and pass in that array. If we wanted to get that back again to a regular array, we would just call toArray on it. Now let me just show you what that looks like if I save that and then launch node with nodemon, point it at my Monet file, that's just going to give me back the contents of my people.json file. If I uncomment this and save it again, we're going to see this is what an empty list looks like. So it's just a list with no objects in it. So we could now go and start to put things into that list now that we've created it. Filtering Immutable Lists Like the other libraries we looked at, let's see how we would go about basically querying an immutable list in Monet to get the items that match a particular filter that we want to apply. So we go and create our filterEq, extremely similar to what we've seen in other libraries, so we're seeing some consistency across the libraries. We use Monet's curry functionality. We say we're going to have a function that takes a property name, a property value that we're going to match against, and then a dataset, or a list. And it's just going to return items that match that value for that property in that list. So we're using the filter function that Monet provides. We set up a curried version of that called married, where we call filterEq and we pass in the married property and a value of true. Then when we call the resulting curried function that we get in married, we're going to just pass in our dataset and we're going to get back the people who meet that filter. So you can see on line 63 we're saying out equals married, we pass in our people list, that is the list we created up on line 54 that is an immutable list in Monet. Now to write it out to the output, be able to see the contents, we call toArray on it, which is something you need to keep in mind when you're working with these data structures in Monet. Like when we were looking at ImmutableJS, if you need to do a lot of thrashing back and forth between the immutable data structure provided by the library and the standard data structures provided by JavaScript such as array, there's a potential performance impact to that. So you want to try to do as much filtering of that data before you have to bring it over to an array to bind it to something that doesn't understand Monet immutable lists. You want to make sure that you are filtering that down and getting it so you're not bringing over a lot of stuff into the array and then applying different filters or slicing it differently inside the array. So if I go ahead and save this, we can see over on the right-hand side, I get a collection of the people who fit that filter. If I were to take this toArray off and save it again, I'm going to get something that's a little harder to work with, or at least to view, because it's just going to show me it's a list of objects. But it doesn't show me the contents of those objects. So by putting the toArray back on, I can actually see this information. Adding Data to Immutable Lists When you're working with the immutable data structures provided by Monet, the head is the first item, and then the tail is everything else. One of the implications of that is you can't easily inject something into the middle of that. Now you could by tearing the whole immutable list apart and rebuilding it with that thing in the middle, but by default you're going to be just adding things to the beginning, so adding a new head, or you're going to be attaching a new tail onto the end. So let's take a look at how we would go about doing that. First we're going to add a new head at the beginning. So we set up a consList and we use our people list we call the .cons function, and pass in just a single newPerson1 we want as the head of the resulting list. Now, pplList is not changed by list. Remember, it's an immutable structure. So although newPerson1 is the beginning of my new list, pplList is unchanged. So if I go ahead and save this, we have this new person added at the beginning, and then the rest of what was originally pplList is the tail. If I were to come over here and say just toArray, so here is the original pplList with Henry Louis Jones as the head. You can see I have 10 records. If I take that out again, I now have 11 records starting with the new person that I pre-pended, and then here is Henry Louis Jones, the beginning of the tail. If I wanted to attach something onto the end, I need to attach a whole new tail. Remember I said earlier how the tail is another immutable list. If I go ahead and put in this next snippet, you can see we're going to, again, append onto pplList, but we need to create an immutable list first. So we're going to create a new immutable list out of the array containing newPerson2 and newPerson3 using that M.List.fromArray. And then we're going to just take all of that once it's been appended onto pplList and store it in my appList. So if I go ahead and save this, I now have 12 people. Now that might seem odd at first. Let's take a look at this. Why do I only have 12? Well, I come back up here and I have Henry Louis Jones. I'm starting with Henry Louis Jones and I'm ending with the two new people that I just appended. And the reason for that is because pplList up here was unchanged. So when I use it again on line 69, pplList does not have that first person that I pre-pended on line 66. If I wanted to get a list with all of those people with newPerson1 at the beginning and newPerson2 and 3 at the end, I would need to change this like this. Then if I go ahead and save, I now have the full list. But that's just showing that my pplList is not changed, and I get a new return value that gets stored in consList. So now I have ending with the two people that I put on as the new tail and up at the top beginning with the person that I put on as the new head. headMaybe() and Empty Lists Besides filtering, how else can I go about getting items out of this list? Well, it depends on the position of the item I'm trying to get. If I want to get just the first item, that's easy. I know that the first item is always going to be referenced by head. So a couple different ways I can go about doing this. Let me comment out a couple of these and we'll take a look at the first one. If I just want to go in and get the first item, this should be Henry Louis Jones. So if I go ahead and save, the head of my pplList, the first item in there, is that Henry Louis Jones. Now if I'm not sure whether or not there is anything in the list, it might be an empty list, then I can use this headMaybe. So you can see here on line 78 I'm creating a new immutable list, but I'm creating it from an empty array. So there's no head or tail, it's just empty. So I can use the headMaybe and you can see I get nothing back. So that's a way to work with a list that is potentially empty. We'll see a different way in just a little bit, but now if I say, well, I want to get something out of a list and I want to get the actual value, well, then we can use the headMaybe, then I'm going to get the actual value with the .some. So I go ahead and save that, and here is the value from inside my list, this is the item that is the head of that list. Now, I can also use a .orSome to specify a default value if there is nothing in the list. So here I'm again creating an immutable list from an empty array, so headMaybe returns nothing. So then I can put the .orSome and supply a default value, take some action, call another function, whatever it is I need to do if that immutable list was empty. Introducing Non-empty Lists So sometimes you might look at doing the whole headMaybe and orSome and some of the other capabilities that Monet provides for working with lists that may not have something in it might be too much. So they provide an interesting construct called a non-empty list. If we take a look at creating a non-empty list, which is often abbreviated in the API as just NEL, if I come in, let's actually start with this first one, we're going to first try to create a non-empty list and pass in undefined as the head. What we're going to get in that case is an error. Because I can't pass in, I can't create an empty non-empty list, and having an undefined head means that it's an empty list. Kind of goes against the grain for what we're calling a non-empty list. It doesn't mean, however, that there needs to be anything actually in the list. So I can create a non-empty list out of an empty array, and the head of the list is that empty array. So if I go ahead and save this, everything works and I don't get my error anymore, and now if I come down and try to go access the head of that non-empty list, I'm going to get back that empty array. So non-empty, it's a little bit of a misnomer; it doesn't mean it actually always has actual content, it just means that I'm not going to get undefined if I try to access it. And we'll be exploring this over the next couple of demos and seeing some of the ways that we can work with the non-empty lists. The full constructor for a non-empty list allows me to specify either just the head as I did on lines 89 and 90, or I can specify the head and the tail. So here I'm going to create a new non-empty list with the first element out of my pplList and then the rest of my pplList, so .head and .tail. If I take a look at this, it's got a whole bunch of stuff in there. Let's see what that stuff actually is by popping toArray on the end here. If I go ahead and save, that's my pplList. I pulled out the first item, it should be my Henry Louis Jones, and that's the head, and then everything else is just the tail. So if I want to go one step further, let me take out a couple more comments here, I'm going to explicitly create an empty tail or a nil tail, and an empty array as the head, and then create a new non-empty list with the two of those. If I go ahead and save, I get my non-empty list, but if I went in and did head, I get my empty array. If I go in and take a look at the tail, I get nil. Okay, so that is the new list that I created with an empty array as the head and then a nil tail. Non-empty Lists - Guaranteed head() and tail() Exploring the head and tail of my non-empty list a little bit further, we already saw how we can create a non-empty list out of an empty array and get the empty array as the head. We can contrast that with, if I try to create just an immutable list out of an empty array and go to get the head, it's going to come back as undefined. So that's what the non-empty list gets me is the ability to have an empty array still a valid head in my list. So to kind of sum things up for our non-empty list, if I have a regular immutable list that I create with fromArray, I can access the head, the first object in it. Same thing with the tail. But if I try to do that with an empty array or an empty list, then trying to access the head or the tail is going to throw an error. The nice thing about the non-empty list is that I can always access the head and the tail, I'm always going to get something back. Now, it may be nil, it may be an empty array, but there's always going to be something there; I won't get an undefined error. So that's a look at some of the capabilities of the library Monet, specifically looking at immutable lists and non-empty lists. We saw a little bit of use of maybe in there and some of the other capabilities that Monet provides. I recommend that if this kind of peaks your interest, you go take a look at the documentation on the Monet website and dig into this a little bit further. Using Functional Libraries in Popular Frameworks What We Do So far everything we've looked at has been strictly in a Vanilla JS environment using just node and a console. We haven't even fired up a browser. Our functional libraries, though, aren't limited to just that usage. In fact, using them alongside other libraries is one way to get a lot of extra mileage out of them. So that's what we're going to cover here. I had a bit of a hard time preparing this module. This course isn't specifically about any of the big three of the JavaScript frameworks, so I have to assume that you're at least familiar with one or more of them. But how could I without tacking hours onto the course, show using each library we've looked at in the course with each of the big three? The fact is that I can't. So the first thing we need to do is decide which framework we're going to cover, because let's face it, there's really only one that matters, and the other two are just also-rans, right? So let's go ahead and crown our winner, shall we? Yeah, let's not. That's actually exactly what we're not going to do. Here's the thing. I couldn't care less which of the big three or any other library, framework, toolkit, whatever you choose. I'm not the least bit interested in a religious war about why or how one is better than the others. Here's all I care about. Honestly, we're all probably too busy for anything but getting our work done. Whatever framework or library you or your team choose is great; I hope you like it! Now let's get back to getting things done. Bear with me for a moment while I get everyone focused on the same stuff. This'll just take a minute. Starting with some very high level generalities, our code operates here in the middle. On the one side, we have generally dumb presentation components that simply display what they're given. On the other side, we have generally dumb data stores of some type that just give us whatever data we ask for and take whatever changes we send its way. On either side of our code is the plumbing that passes things back and forth. For the most part, we don't do anything here the vast majority of the time. Realizing this is a gross oversimplification in a lot of ways and there are always edge cases and exceptions, it still provides value, because it leaves us with the majority of our time and effort with just one thing we need to focus on. So what really happens here? That's what we're going to cover as we look at how the function libraries we've covered in the course can come into play. Still talking in generalities, in the middle there we manipulate data. That's it. Regardless of how our code gets the data and where it's going to send it when it's done, we need to slice and dice it, filters, sorts, CRUD, et cetera. So let's drill in on that a little bit. This certainly isn't an exhaustive list of the various data operations our code does on a regular basis, but it's a good sampling. Now do you notice anything about this list? It seems an awful lot like the various operations the libraries we looked at earlier offer us. To be honest, Folktale is light on a lot of this, especially for the pieces we covered it, maybe, result, and validation, but it's still fair to call it a player. This list isn't all-inclusive; it's really just what would fit easily on one slide, so I won't rule Folktale out. Besides, its maybe, result, and validation are quite good, and also important parts of what we do. The Money Slide I'll freely admit that I just took you on a bit of a forced march down a particular path, but it was quite intentional. I was leading you to a conclusion, namely that it doesn't matter which framework you choose. The framework is completely irrelevant when it comes to using one or more of these functional libraries. React, View, Angular, something else, just plain Vanilla JavaScript, or whatever new library is the shiny object we'll all be chasing six months from now can all play nicely with Immutable, Ramda, Folktale, FKit, Sanctuary, Monet, and probably just about any other decent functional library out there. Remember this slide from way back at the beginning of the course? Remember I said that if you mastered these six things that you'd be well on your way to mastering functional programming? Well, mastering these will also allow you to apply them to your work with Angular, View, React, or whatever. In fact, if you really want to achieve programming Nirvana, not only should your framework choice be irrelevant, but you ought to be able to take all or nearly all of your functional data manipulation code and move it from one framework to any other with little to no rework. Looking back at this slide again, if these two arrows are the only ways that data gets in or out of our code processes, what does that remind you of? Yeah, it's a little bit like pure functions. Everything we need gets passed into us, and we always return the same thing for a given set of inputs. Sounds an awful lot like pure functions applied to UI and data, an awful lot. See? I did it again. I led you down a path. But this one gets us to the money slide. If you take nothing else away from this module, and really this entire course, remember this, the disciple of functional programming is more important than the implementation details. And that includes which library you choose to help you with your functional programming or no library at all. It includes which library or framework you choose to wrap around your functional programming. Keeping in mind two other things I said way back at the beginning of the course about functional programming not being the amazing cure-all and keeping your eye on the goal, avoiding distractions. Adding functional programming skills and knowledge to your tool belt is not going to be a bad thing. Know it enough to use it where it provides value and skip it where it doesn't. Know it enough, and you can swap implementation libraries in and out with little to no pain. So that gets us to the end. A little different in this module than perhaps you expected, but I really think that the implementation library you choose is immaterial, and which framework you try to wrap around it, irrelevant. All of the functional libraries we covered are good, each with their own strengths and weaknesses. I hope I gave you a good overview of them all and you've narrowed them down to maybe a few that you want to check out. Thanks for watching! Feel free to strike up a discussion in the discussion section of the Pluralsight website, or head over to my blog. It's a little newish as I'm recording this in early 2018, but I'll be adding more and more material about the programming aspects of our product as we get closer to release and then beyond, as well as various things about startup life, running a business, etc. Thanks for watching! Course author David Mann Dave is a start-up co-founder and CTO, an 11-time Microsoft MVP, and full-stack web developer, trainer and author focusing on JavaScript, NodeJS, document DBs and C#. Course info LevelIntermediate Rating (14) My rating Duration2h 59m Released1 Jun 2018 Share course