The term functor comes from category theory in which a functor is a date type used to preserve the structure of data as it's transformed from one category to another. We can recreate these data types in JavaScript by using regular factory functions.
In this lesson, we learn about the properties our data type must have in order to be considered a true functor. By the end of the lesson you will have created a factory function for creating Identity
functors.
Instructor: [0:00] The term Functor comes in category theory, in which a Functor is a data type that preserves the structure of a piece of data as it is mapped from one category to another. Although the name may sound foreign, we work with Functors all the time in JavaScript. Given that array data type is technically a Functor.
[0:23] As you can see, it provides us with a container to wrap our value and it also provides us with a map interface. The map interface is arguably the most important part of a Functor as it allows us to transform a value from one type to another without causing any harm to our data.
[0:44] There're many common Functors in [inaudible] that you find working in functional programing. Now, we're going to implement the Identity Functor, which is the most basic of them all.
[0:57] Now, we're just going to take a value x and return an object. Now, inside our body, we can add different methods that will allow us to act on the data with which our Functor is holding.
[1:11] Now, as you just learned, map is crucial. This will be the first method that we'll add. This map is going to take a function which will then be applied to the value being held inside of our container.
[1:24] From this, we're going to return a new container because we want to be able to preserve that context. This way, we know we have a continued safety transforming of values until it's time to pull it out and use it. That leads us to our next method, valueOf.
[1:42] As you can see, valueOf is just going to be called with no arguments, and it's just going to allow us to unbox our data that's being held by our Identity Functor.
[1:55] Now, we can call our Identity Function and pass in the value of 10 into our box, and we'll see that we had these map and valueOf methods on there. Now if we add an inspect method, we'll see that it's just automatically going to be logged in for us. We'll set it up to just so it prints identity and then the value, and we see identity 10.
[2:23] We have this Identity Functor, but we need to be able to make sure that it abides by the Functor laws, or else we won't be able to compose it with other Functors and leverage all the true power that as great data types give to us.
[2:40] Now, the two Functor laws are identity and composition. If you're familiar with function with composition, then you might be familiar with these.
[2:50] First, I am going to create a variable and set it equal to the identity function with some number, 1992. Below, I'm just going to add the identity function which we'll use to test.
[3:03] Now that we have our test property set up, I am going to create two variables, A and B. A is just going to be equal to that x that we just created. Following this, we're just going to set B to the value of A that map with the identity function.
[3:21] Now that we have that setup, I'm going to call that compare function I've imported above and I'm going to pass in a.map ID to the first argument and then b.map ID.
[3:35] As we see, if we evaluate them, that we're both getting true. One thing to point out is that this compare function is calling two string on both these values under the hood.
[3:47] This is because of how JavaScript treats non-primitive values like objects, specifically they won't allow us to test for equivalence. Thus forcing us to transform our values to a primitive value like a string before comparing.
[4:02] Carrying on though, the next law we need to test is the composition. To test composition, we need to map over our Identity Functor, and we're just going to pass in the squareNumbers function, which is going to square 2000, and then we're going to map again and pass in timesTen, which is going to multiply the result of squareNumbers times 2000 timesTen.
[4:35] Now, to prove this equal, we're only going to use one map and we're going to use map's callback function to transform our value in one fell swoop.
[4:46] Now, instead of chaining maps, we're passing in squareNumbers to our timesTen function, and the most nested parted part of this is our x value.
[4:59] We should know that these functions are going to fire off from inner router, and as a result of that, comparing the function up top where squareNumbers is applied first, and the timesTen is applied second, will give us the same value as we just produced here on the second line.
[5:22] That just about wraps up this video on Functors. Just to recap, in order for a data type to be a Functor, it must implement a map method and it also must abide by the identity and composition laws that we just tested out.
Member comments are a way for members to communicate, interact, and ask questions about a lesson.
The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io
Be on-Topic
Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.
Avoid meta-discussion
Code Problems?
Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context
Details and Context
Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!