A functor is a type class that generalizes the map transformation concept across different data structures, allowing a single API to transform any mappable container (like lists, options, tries, or custom trees) without code duplication by providing a uniform map method that transforms values while preserving the container's structure.
Understanding Functors in Scala: A Practical Guide for Functional Programming
Added:welcome back to rock the jvm in 2021 folks i'm daniel and this will be the first video of the year 2021 and i'm going to discuss about fun tours in functional programming now as always i'm going to write scala in this video but this concept will apply to other types languages as well for example typescript or java or c plus plus or any other typed languages that you are familiar with so for this video i'm going to assume some familiarity with lists and options as mappable containers and i'm going to demonstrate what this means in the video now as a recommendation as always i'll recommend that you code alongside me and when you need to refresh your memory about functors just refer back to this video or to the blog article at blog.roc.jv alright so that being said let's get back to the code so in this project i'm using scala 3 but this concept is applicable to scala 2 as well and in the previous videos of rock the jvm i've already shown you how you can create a skull3 project you can do file new project in intellij idea and in the wizard that pops up you will select scala and dottie experimental here on the right and after you hit on next you can simply follow the rest of the wizard it should be really straightforward as long as you have intellij idea and i'm using the version 2020.2 which is pretty recent and has some dotty experimental support all right so let's get back to this video and to the code that i'm about to write this video will be pretty general because although we will write skull this article will focus more on the concept than on some very specific apis now this is one of the lessons of the cats course of rock the jvm which we look at in general terms in this video so in the cats course which i'm going to leave a link in the video we talk about functors in much more detail with some exercises and whatnot all right now let's get back to functor so pure functional programming deals with immutable values so if you want to transform a data structure we will need to create another one not modify the old data structure so you're probably familiar with the famous map method on lists so i'm going to define a value let's call this an incremented list as list one two three and assuming that i want to transform this list and increment each element by one i would say map and to the map function i would pass a lambda that given an int you transform it to something else so given an x i'm going to return x plus 1.
so this will be the list 2 3 4 and this will be a completely new data structure but i already assume that you know this already the thing is that this map transformation concept can be applied to other data structures as well and scala programmers are all too familiar with the concept of options which are data structures which may contain zero or one value so if i define an option as option int and on the right hand side i say sum2 this will be an option that contains one value so you can think of an option as a list with one element and i'm not going to explain why this is a useful data structure we use options to validate and process values which may not exist so that we can circumvent defensive code with null checking all right so we use options as a solution to this problem so these options may contain zero or one value and a try which is a similar data structure which can wrap a desired value or an exception if that computation fail this is an equivalent or a similar data structure so i'm going to define a try as tri-int with a capital t and i'm going to say success with the value let's say 42 and for this i'm going to need to import sky util try and scale util success because these are not automatically imported so try is a very similar data structure to option in the sense that it can wrap a desired value or it can wrap an exception if that computation if that expression fails all right and java folks by the way they also use the optional type with the same semantics as scala's option and other type languages have very similar data structures in place now the thing is that the map transformation that you saw here on lists is also applicable to options tries and other data structures as well we've covered some of those in the monads video which i really recommend you watch on the youtube channel and i'm going to probably dive deeper into those in another video so if i want to transform this option i would say a transform option as an option map x arrow x times 10 for example and this will be another option instance which contains the value 20 instead of 2 and similarly a transformed try would be a try dot map x arrow x times 10 and this will be a success with 420 wrapped inside so this map concept is applicable to lists and to other kinds of containers like this and to generalize this concept i'm going to introduce the concept of functors so for purely practical reasons let's consider a very simple example that wants to transform a list an option and a try by multiplying its inside value with 10.
so i'm going to define three methods let's call this do 10x list which takes a list of integers as argument and returns another list of integers and i'm going to say list map underscore times 10 which is the same as list.map and with this kind of lambda x error x times 10.
and i'm going to multiplicate this method so i'm going to duplicate this and i'm going to make it applicable to options and tries because that's the best that we can do right now so i'm going to say do 10x option with an option as option ins and this will return another option and and i'm going to say option map and underscore x 10 as well and i'm going to copy that and i'm going to say do 10x try and i'm going to use try in this time around and i'm going to simply say a try and a try map underscore times 10. so notice that we have duplicated code here because there's nothing better than we can do if you want to support another kind of data structure in your api you would have to define yet another method that would do basically the exact same thing because if you look at the implementation of these methods they are basically identical it's the argument dot map and then you pass on that function however there's no need to repeat ourselves because we've established that this map concept is so called transferable so we can create an interface for it and in scala a transferable concept can be very easily expressed as a type class and we also have a video on type classes in the rock the jvm channel as well so we will name this concept a functor and i'm going to define a trait for it so i'm going to define a trait functor and this will be a generic in another type argument which is itself generic so i'm going to say functor c underscore where c will stand for a type which is itself generic for example list or option or try so this functor thing will contain a method called map but this map will look a little bit different than the map that you normally see in the standard library so you will need to supply some type arguments a and b which are the concrete types of the container that you initially have and the container that you want to obtain so the first argument will be a container which will be a c of a for example a list of int for example and a function which transforms an a to a b and then at the end of the function you will obtain a container with that type b so this is the functor trait so the definition is pretty compact by but i think you will be able to read it so in order to use this map concept on various data structures we will need to create implementations of this functor trait for various data structures that we'd like to support so for example on lists we would have the following i'm going to define a given value and obviously we have a video on givens on the rock the jvm channel i'm going to link it in the description if you are interested in seeing that for scala 3. so i'm going to use the skull 3 syntax so i'm going to say given list functor as functor list all right so notice that functor takes as type argument the list type itself which may itself be generic so i'm going to use the list type just as it is and i'm going to need to override the map method so i'm going to say def map and the id is smart enough to suggest an implementation a function signature for me so override def map with the exact signature that i wrote in the trait and as implementation i'm just going to use the map method that the container initially has because the list already has a map method so i'm going to say container dot map f all right so this functor is an instance of functor for list where the map method just applies the standard libraries map method on the initial container now why is this useful why do we want to simply reuse the standard library map in another map function well the interesting thing is that once we have functor instances for all the data structures that we'd like to support for example list and option and try or whatever other data structures you might want to support you can generalize this api so instead of having three methods and needing to add a new method every single time you want to support a new data structure instead what you can have is a stable api which is general enough so i'm going to define def let's call this do 10x and i'm going to simply keep it at that so do 10x but i'm going to add a type argument and this will be a higher kind of type c which can be list option try or whatever else you might want to support and i'm going to use the container which is instead of a list in is going to be a c of int but i'm going to assume the presence of a functor for this kind of container in scope so that we can use it in the map so i'm going to say using functor as functor of that container type c and i'm going to obtain a c of int where the implementation is going to be instead of container map underscore times 10 i'm going to use the functor so i'm going to say functor map with the initial container and the underscore times 10 function that i used to use on this other multiplicated api so this will be the duplicated api and this is the one function stable api now why is this useful why is this valuable this kind of code is valuable because we've reduced this api to a single method and we can now use it on different data structures provided we have a given functor in scope so for example this call do 10x with the list one two three simply works just as it is so instead of me needing to do do 10x list with list123 where the presence of this api method would require me to support list instead of doing that and i can simply call the general api do 10x with the container list 123 provided i have a functor list in scope so the functor list will be implicitly passed by the compiler here list functor so this would be injected by the compiler automatically all right but i would have to comment that because the compiler doesn't like the second argument being passed explicitly as this structure over here i would have to use using for the compiler to accept it so notice that the compiler can automatically inject list functor just as it is because i've defined it as a given instance so so far this do 10x does exactly as this duplicated api used to do given we have the functors for list option and try in scope but these are easy examples because all of them already support a map method this api is even more powerful because we can also choose to support data structures that does not have the map method inherently supported and so i'm going to define a very quick binary tree kind of data structure and i'm going to show you how this api can also be used to support this new data structure just by defining a functor in scope so i'm going to define a trait tree and i'm going to make it covariant and i'm going to create two case classes so case class leaf of plus t and this will wrap a value of type t and this extends tree of t so this tree data structure will either be leaf nodes which will wrap simple values or they can be binary branches so i'm going to define case class branch of plus t and this will be a value this will contain a value of type t and a left node which is of type tree t and a write node which is of type tree t and this extends tree t now just to make this super compact i'm also going to define some factory methods in a companion object so i'm going to say object tree and i'm going to define a method called leaf which takes an argument t and wraps a value and this will return a treaty this is very very important you need to define the return type of these factory methods as the general trait type and in the implementation you can either choose to provide a leaf or a branch so i'm going to say leaf value and i'm going to define another method called branch which takes the type argument t and then three constructor arguments i'm going to pass these exact things as they are i'm going to make this branch method return a tree t this is also very important so we specify the general interface and i'm going to say branch with value left and right so we've defined a very small data structure which denotes a binary tree this can either be a leaf node or a branch node and i'm going to show you how this stable api can simply support this new data structure just by adding another functor for this data structure in scope so this is exactly what i'm going to do i'm going to define a functor for the stream so i'm going to define it as a given instance as well so i'm going to say given tree functor let me scroll down so you can see better as functor tree and this functor tree will only need to support this map function that the functor trade will need to define so i'm going to define map and intellij will suggest a method definition and the map function will take a container as a tree of a and a function from a to b and this will return a tree of b now i'm going to simply use pattern matching here so i'm going to say container match and in case we have a leaf containing wrapping a value then i'm going to return another leaf node so i'm going to say leaf with f of value so this will be a leaf of b this time around and in case i have a branch with a value left and right i'm going to simply apply the function f to this value and then i'm going to recursively apply map on this left and right subtrees over here so i'm going to say branch with f of value and on the left hand side i'm going to use map with left and f and map with right and f all right so we simply recursively call map on the left and right sub trees over here cool so let me show you how this do 10x stable api can suddenly support a tree data structure so i'm going to define a val tree and i'm going to say tree.branch and i'm going to say 1 this is the root note and the left node is going to be tree branch with the node 2 and then let me use two leaf nodes so i'm going to say leaf 3 or 3 dot leaf 3 and 3 dot leaf 4 all right so this whole tree is the left subtree of the root node one and the right subtree let me just use leaf five or tree dot leaf all right so we have one as the root node on the left hand side we have yet another subtree with 2 3 4 and on the right subtree of the root note 1 we have a simple leaf 5. cool let's process this tree so i'm going to simply say do 10x on this tree and notice that this stable api can suddenly support this tree because we've defined a given instance of functor tree in scope and so the compiler can inject that automatically for us and so because i've created this whole file here as an object i can define a main method inside so i'm going to say main and then type enter and then i'm going to simply print line this new value over here so i'm going to cut it out and print line inside so let me go ahead and run this and you'll notice that we obtain a tree whose values are processed in the exact same way while keeping the same structure so we have 10 20 30 40 and 50. so now it is the time where we should stand back and notice the power of a functor it allows us to generalize an api and process any kind of mappable data structure in a uniform way without needing to repeat ourselves so given a functor in scope we basically assume that this container c is mappable in some way and through the definition or through the implementation of a functor for that type we have just made that type mappable just like a list just like an option like a try and many other data structures so this was an example of how your stable api using a functor can suddenly support a completely new data structure without needing to modify the original api all right so i hope this is valuable now i'm going to go one step further because with scholar 3's extension methods or with implicit classes in scholar 2 we can attach the map method the natural map method to a data structure that normally does not have it so i'm going to define an extension method so i'm going to say extension this is a new kind of structure in skull 3.
and for an extension method i need to supply all the type arguments in advance so i need to supply the type argument c which is itself generic the type argument a which is the type of the initial container and the type b of the resulting container so i need to supply all the three type arguments in advance and i'm going to wrap a container as a c of a so given a c of a this c of a will suddenly have a map method that i'm going to define later using a functor as functor c so extension for the container c of a given a functor c in scope i'm going to define a map method that given a function from a to b that you pass as argument i'm going to simply call functor map with container and that function now this structure is pretty compact so what this means is that if you have the type c of a then this type c of a for example a tree of int this can suddenly have a map method if you have a functoring scope where if you call the map method on this container the implementation of this map method would be the functor that you use as a given value functor.map with that ignition container and the function f that you pass inside so i'm pretty sure this is still very abstract so i'm going to simply show you how this extension method would work on this tree so i'm going to define another value called 10x tree and i'm going to simply say tree dot map so tree is a tree of int and because we have a functor of tree in scope the scala compiler can naturally attach this map method which takes a single argument a function from a to b so i'm going to say underscore times 10 and what the compiler rewrites that to is functor of that tree which is tree functor map with that initial container which is the tree and the function underscore times 10. so this is what the compiler rewrites this expression to but normally you wouldn't see this so this would be simply transparent to you as if the tree data structure was mappable just like a list so this is the power of an extension method using a given instance of functor so i'm going to leave this for your reference so notice how you can make a new data structure mappable with a new functor and obviously if i print this out so if i print line 10x3 i'm going to see the exact same result so if i right click and run this i'm going to see the exact same process tree here in the output so notice how a functor can extend the original api of your data structures so functors are a pretty powerful concept in functional programming i hope this video was valuable if you did like this video go ahead and give it a thumbs up and subscribe to the channel for more videos like this and follow me on twitter and linkedin for fresh updates on upcoming material and check out the blog for the written version of this video and check out the rock the jvm website and the cats course for more content like this in the meantime i'm danielle signing off [Music] [Applause] [Music]
Up Next

Haskell Functors Explained: fmap and Type Constructors Tutorial
@scrilla103
16.8K views•2014-05-06

BitTorrent Protocol Explained: Piece Selection & Peer Choking
@StevenGordonAU
481 views•2013-02-22

HTTP Requests Explained: GET, POST, PUT, DELETE
@codecademy
103.1K views•2021-10-07

Enigma Machine Mechanics: WWII Encryption Explained
@JaredOwen
13.2M views•2021-12-11
Related Study Plans & Knowledge Roadmaps
Structured learning paths in Computer Science


![Venners & Sommers: Thinking in Scala 3 Types [Scala Days 2025]](https://i.ytimg.com/vi_webp/qtjN8R8G-ec/maxresdefault.webp)







































