{"id":"Nkc9wYvHC1Y","title":"Lesson 8: Functor, Applicative, and Action","description":"When we perform actions on the ledger, such as exercising a choice or fetching a contract, we need to know that these actions are different from executing pure expressions. The two differences are that actions on the ledger have a context which changes their outcomes, and they have side effects on the ledger to understand how actions work. \n\n00:15 Pure Expressions\n00:39 Actions\n01:09 Functor\n02:59 Applicative\n05:31 Action Typeclass\n07:47 Review\n\nFor a better learning experience, sign up and enroll in this free course at: https://daml.talentlms.com/plus/catalog/courses/143","channel_name":"Digital Asset Training","published_at":"2025-02-20T00:00:00.000Z","thumbnail_url":"https://i.ytimg.com/vi/Nkc9wYvHC1Y/hqdefault.jpg","transcript_text":"functors, applicatives, and actions are critical to understand how transactions are submitted and perform in ledgers. An important point to keep in mind when working with the Canton Ledger is the difference between a pure expression and an action. Pure expressions can be computed from the values of its arguments. You could write a pure expression down on a piece of paper without any context or side effects. For example, adding two numbers or sorting a list of integers doesn't require any contextual information and doesn't have any external side effects. The result of these operations is always the same for the same value of the same arguments. Actions, on the other hand, take place within a context. For example, the state of the ledger. The same action, an update to the ledger, can result in two different outcomes depending on when it's executed. Create contract action based on a template with a contract key may succeed or fail depending on whether an active contract with the same value of the key already exists on the ledger. To understand how actions work, we first need to understand a few new type classes. The first of which is called a Functor. Functor is a typeclass that's used for data types that can be mapped over for this purpose, an instance of a function typeclass must implement fmap functions. When we look at its signature, it takes a function, A maps to B, and F A, which means functor with values of type A. It then maps it to a functor with values of type B. Note that F here means functor and not function. The function that a functor data type must implement is called fmap. An example of such a type is a list. The list data type implements the fmap in what we call a map. As you can see in the signature, it takes a function that maps values of type A to values of type B and A list containing values of type A. The map function applies the function to each element in the list and returns the list containing values of type B. In this example, if X is a list of integers and we apply a map function with raise to the power of two to the list, the result in each element in the list will be raised to the power of two. You'll often find fmap being denoted as a dollar sign between two angle brackets in the documentation. This notation is fmap's synonym where fmap is used in a prefix notation and the function name is followed by its input arguments. The dollar notation is used as an infix notation. The parenthetical plus two function here means we take another argument and add to it. So parenthetical plus two x means x plus. The plus two function applied to the list will be applied to each element resulting in a list with three, four, and five as its elements. Taking the idea of functors a step further, we have another typeclass called Applicative. Applicative takes a functor that contains one or more functors and applies those functors to values in another function. The function for this typeclass is denoted as a star enclosed in angle brackets, and simply called the applicative function. The applicative function takes a functor value that has a function in it, and another functor and extracts the function from the first functor and maps it over the second one in the definition shown here. F denotes the functor and an A maps to B denotes a function. So we can read this as an applicative function, takes a functor F that contains functions, that map values of type A to values of type B. It takes a functor containing values of Type A and it returns of functor containing values of type B. Let's take a look at some examples to see how this works. In the first statement, we have three functors in a list. Multiply by zero, add 100, and raise to the power of two. So this is the first input, which is a functor with functions in it. The second input is another functor containing some values. For example, one, two, and three. The applicative function, shown as infix, function will apply the functors from the first functor on the left, one by one, to the values in the second functor on the right, giving us the output as shown here. In the second example, the function is given without one of the operands, and as these are binary functions, they'll need two operands. So the first multiplication function is taken from the first functor and applied to the value one, which will give a partial application of the function. Then the second applicative function will apply this partial function to the first value in the third functor, making it one times three resulting in the value three as shown in the output. In the same way, each function is applied to each value in the functors from left to right to produce the final answer. The third example is a combination of functor and applicative operations. It starts with a multiplication function applied to all three elements in the first list. This allows for partial functors, which are then applied to the second list producing nine values in the output. As you can see, the basic essence of an applicative function is applying the functions in a functor to values in another functor. It's this idea which is applied to perform actions on the ledger. And for that we need to look at one more typeclass called action. Action typeclass is an applicative type that sequentially composes actions passing any value returned by the first action as an argument to the next. Its function is represented as the bind operator, which is two right angle brackets and an equal sign. This bind operator pipes the result of one action into the next. The definition shows that the bind operator. Action M, that returns a value of type A. A function that maps values of type A to an action that returns a value of type B. And finally, it returns the action that returns a value of type B. Here's our example that demonstrates how the bind operator works. Let's say we have a function safeDiv that takes two ints, X and Y and returns an optional int. If Y is zero, then it returns none. Else it computes X divided by Y and returns the result as some int. We have another function reduce that takes an int X and returns an optional int. If X is zero or negative, then it returns none. Else it computes X minus one and returns it as some int. We want to pipe these functions in a sequence. In the first statement, we have safe div four two, which gives us some two. In the second statement, we have safeDiv four zero, which gives us none. In the third statement, we have safeDiv 4 2, which is then piped into reduce and we get some 1. And in the fourth statement, we have safeDiv four piped into reduce giving us none. In this way, the bind operator allows sequencing a series of functions. An alternative to using the bind operator is the do-block that we've used in Daml several times. If we define a function, say binding actions, that takes two ins and then performs safeDiv, followed by reduce in a sequence, we can represent the same functionality by using a do-block where we first bind the results of safeDiv to a variable name Z, and then feed it into reduce. The left arrow indicates binding that is specifically used when the expression on the right side is an action. Do blocks enable sequencing multiple actions together in this way. So let's summarize. When we perform actions on the ledger, such as exercising a choice or fetching a contract, we need to know that these actions are different from executing pure expressions. The two differences are that actions on the ledger have a context which changes their outcomes, and they have side effects on the ledger to understand how actions work. We first looked at functors and then applicatives. Functor is a typeclass that has a function fmap. It takes a function that maps A to B and applies to a functor containing A and returns a functor containing B. A good example for a functor is a list. Applicative is a typeclass that starts with a functor F that contains a function that maps A to B. It also takes a functor containing A and returns a functor containing B. We can think of this as a first functor containing functions and a second functor containing some values. The functions from the first functor are applied sequentially to the values in the second functor. The third concept is an action typeclass, which has a binding operator that allows us to pipe the output of one function into the next in a sequence. The sequential execution of functors can be put into a do-block, making it easier to read and write actions.","transcript_synced_at":"2026-10-26T03:57:06.778Z","segments":[{"start_seconds":1,"text":"functors, applicatives, and actions are critical to understand how transactions are submitted and perform in ledgers.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=1s"},{"start_seconds":8,"text":"An important point to keep in mind when working with the Canton Ledger is the difference between a pure expression and an action. Pure expressions can be computed from the values of its arguments.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=8s"},{"start_seconds":19,"text":"You could write a pure expression down on a piece of paper without any context or side effects.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=19s"},{"start_seconds":24,"text":"For example, adding two numbers or sorting a list of integers doesn't require any contextual information and doesn't have any external side effects.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=24s"},{"start_seconds":33,"text":"The result of these operations is always the same for the same value of the same arguments. Actions, on the other hand, take place within a context.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=33s"},{"start_seconds":42,"text":"For example, the state of the ledger.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=42s"},{"start_seconds":44,"text":"The same action, an update to the ledger, can result in two different outcomes depending on when it's executed.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=44s"},{"start_seconds":51,"text":"Create contract action based on a template with a contract key may succeed or fail depending on whether an active contract with the same value of the key already exists on the ledger.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=51s"},{"start_seconds":63,"text":"To understand how actions work, we first need to understand a few new type classes. The first of which is called a Functor.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=63s"},{"start_seconds":69,"text":"Functor is a typeclass that's used for data types that can be mapped over for this purpose, an instance of a function typeclass must implement fmap functions.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=69s"},{"start_seconds":80,"text":"When we look at its signature, it takes a function, A maps to B, and F A, which means functor with values of type A.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=80s"},{"start_seconds":88,"text":"It then maps it to a functor with values of type B. Note that F here means functor and not function.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=88s"},{"start_seconds":96,"text":"The function that a functor data type must implement is called fmap. An example of such a type is a list.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=96s"},{"start_seconds":104,"text":"The list data type implements the fmap in what we call a map.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=104s"},{"start_seconds":108,"text":"As you can see in the signature, it takes a function that maps values of type A to values of type B and A list containing values of type A.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=108s"},{"start_seconds":117,"text":"The map function applies the function to each element in the list and returns the list containing values of type B.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=117s"},{"start_seconds":124,"text":"In this example, if X is a list of integers and we apply a map function with raise to the power of two to the list, the result in each element in the list will be raised to the power of two.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=124s"},{"start_seconds":136,"text":"You'll often find fmap being denoted as a dollar sign between two angle brackets in the documentation.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=136s"},{"start_seconds":143,"text":"This notation is fmap's synonym where fmap is used in a prefix notation and the function name is followed by its input arguments.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=143s"},{"start_seconds":151,"text":"The dollar notation is used as an infix notation.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=151s"},{"start_seconds":155,"text":"The parenthetical plus two function here means we take another argument and add to it. So parenthetical plus two x means x plus.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=155s"},{"start_seconds":165,"text":"The plus two function applied to the list will be applied to each element resulting in a list with three, four, and five as its elements.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=165s"},{"start_seconds":174,"text":"Taking the idea of functors a step further, we have another typeclass called Applicative.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=174s"},{"start_seconds":179,"text":"Applicative takes a functor that contains one or more functors and applies those functors to values in another function.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=179s"},{"start_seconds":186,"text":"The function for this typeclass is denoted as a star enclosed in angle brackets, and simply called the applicative function.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=186s"},{"start_seconds":193,"text":"The applicative function takes a functor value that has a function in it, and another functor and extracts the function from the first functor and maps it over the second one in the definition shown here.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=193s"},{"start_seconds":207,"text":"F denotes the functor and an A maps to B denotes a function.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=207s"},{"start_seconds":211,"text":"So we can read this as an applicative function, takes a functor F that contains functions, that map values of type A to values of type B.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=211s"},{"start_seconds":221,"text":"It takes a functor containing values of Type A and it returns of functor containing values of type B. Let's take a look at some examples to see how this works.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=221s"},{"start_seconds":230,"text":"In the first statement, we have three functors in a list. Multiply by zero, add 100, and raise to the power of two.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=230s"},{"start_seconds":238,"text":"So this is the first input, which is a functor with functions in it. The second input is another functor containing some values.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=238s"},{"start_seconds":247,"text":"For example, one, two, and three. The applicative function, shown as infix, function will apply the functors from the","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=247s"},{"start_seconds":254,"text":"first functor on the left, one by one, to the values in the second functor on the right, giving us the output as shown here.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=254s"},{"start_seconds":262,"text":"In the second example, the function is given without one of the operands, and as these are binary functions, they'll need two operands.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=262s"},{"start_seconds":271,"text":"So the first multiplication function is taken from the first functor and applied to the value one, which will give a partial application of the function.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=271s"},{"start_seconds":280,"text":"Then the second applicative function will apply this partial function to the first value in the third functor, making it one times three resulting in the value three as shown in the output.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=280s"},{"start_seconds":291,"text":"In the same way, each function is applied to each value in the functors from left to right to produce the final answer.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=291s"},{"start_seconds":298,"text":"The third example is a combination of functor and applicative operations.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=298s"},{"start_seconds":303,"text":"It starts with a multiplication function applied to all three elements in the first list.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=303s"},{"start_seconds":308,"text":"This allows for partial functors, which are then applied to the second list producing nine values in the output.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=308s"},{"start_seconds":314,"text":"As you can see, the basic essence of an applicative function is applying the functions in a functor to values in another functor.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=314s"},{"start_seconds":323,"text":"It's this idea which is applied to perform actions on the ledger. And for that we need to look at one more typeclass called action.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=323s"},{"start_seconds":331,"text":"Action typeclass is an applicative type that sequentially composes actions passing any value returned by the first action as an argument to the next.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=331s"},{"start_seconds":340,"text":"Its function is represented as the bind operator, which is two right angle brackets and an equal sign.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=340s"},{"start_seconds":347,"text":"This bind operator pipes the result of one action into the next. The definition shows that the bind operator.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=347s"},{"start_seconds":354,"text":"Action M, that returns a value of type A. A function that maps values of type A to an action that returns a value of type B.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=354s"},{"start_seconds":364,"text":"And finally, it returns the action that returns a value of type B. Here's our example that demonstrates how the bind operator works.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=364s"},{"start_seconds":372,"text":"Let's say we have a function safeDiv that takes two ints, X and Y and returns an optional int. If Y is zero, then it returns none.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=372s"},{"start_seconds":381,"text":"Else it computes X divided by Y and returns the result as some int. We have another function reduce that takes an int X and returns an optional int.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=381s"},{"start_seconds":392,"text":"If X is zero or negative, then it returns none. Else it computes X minus one and returns it as some int.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=392s"},{"start_seconds":400,"text":"We want to pipe these functions in a sequence. In the first statement, we have safe div four two, which gives us some two.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=400s"},{"start_seconds":408,"text":"In the second statement, we have safeDiv four zero, which gives us none.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=408s"},{"start_seconds":413,"text":"In the third statement, we have safeDiv 4 2, which is then piped into reduce and we get some 1.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=413s"},{"start_seconds":420,"text":"And in the fourth statement, we have safeDiv four piped into reduce giving us none.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=420s"},{"start_seconds":427,"text":"In this way, the bind operator allows sequencing a series of functions.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=427s"},{"start_seconds":432,"text":"An alternative to using the bind operator is the do-block that we've used in Daml several times.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=432s"},{"start_seconds":437,"text":"If we define a function, say binding actions, that takes two ins and then performs safeDiv, followed by reduce in a sequence, we can represent","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=437s"},{"start_seconds":446,"text":"the same functionality by using a do-block where we first bind the results of safeDiv to a variable name Z, and then feed it into reduce.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=446s"},{"start_seconds":456,"text":"The left arrow indicates binding that is specifically used when the expression on the right side is an action.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=456s"},{"start_seconds":462,"text":"Do blocks enable sequencing multiple actions together in this way. So let's summarize.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=462s"},{"start_seconds":469,"text":"When we perform actions on the ledger, such as exercising a choice or fetching a contract, we need to know that these actions are different from executing pure expressions.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=469s"},{"start_seconds":478,"text":"The two differences are that actions on the ledger have a context which changes their outcomes, and they have side effects on the ledger to understand how actions work.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=478s"},{"start_seconds":487,"text":"We first looked at functors and then applicatives. Functor is a typeclass that has a function fmap.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=487s"},{"start_seconds":494,"text":"It takes a function that maps A to B and applies to a functor containing A and returns a functor containing B. A good example for a functor is a list.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=494s"},{"start_seconds":504,"text":"Applicative is a typeclass that starts with a functor F that contains a function that maps A to B. It also takes a functor containing A and returns a functor containing B.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=504s"},{"start_seconds":514,"text":"We can think of this as a first functor containing functions and a second functor containing some values.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=514s"},{"start_seconds":521,"text":"The functions from the first functor are applied sequentially to the values in the second functor.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=521s"},{"start_seconds":528,"text":"The third concept is an action typeclass, which has a binding operator that allows us to pipe the output of one function into the next in a sequence.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=528s"},{"start_seconds":536,"text":"The sequential execution of functors can be put into a do-block, making it easier to read and write actions.","url":"https://www.youtube.com/watch?v=Nkc9wYvHC1Y&t=536s"}],"youtube_url":"https://youtube.com/watch?v=Nkc9wYvHC1Y","url":"https://ccpedia.xyz/videos/Nkc9wYvHC1Y"}