Lesson 11: Type Variables
Nothing is loaded from YouTube until you press play, and then without tracking cookies.
About this video
02:33 Parameterized functions 03:11 Optional data type 04:44 Review
For a better learning experience, sign up and enroll in this free course at: daml.talentlms.com/plus/catalog/courses/141
Transcript
970 wordsCaptions as YouTube publishes them, usually machine-generated, so names such as Daml and Canton can be misheard.
- 0:00
Type variables or type parameters help us define functions and data structures at a level of abstraction above the concrete data types. They allow us to write functions that are generic in nature and take a wider range of data types than just a specific concrete data type, such as int or text.
- 0:17
An example of a parameterized data type is a list that can store anything, an in text or other lists and so on. Same with tuples. Additionally, the functions using lists, such as length, are also able to handle any type of data stored in the list.
- 0:34
So how do we define data types and functions that can deal with a generic data type? Before we look into that, let's see how some library functions that use type variables are defined. Here's an example of an add function that takes two ints and gives an int is a return. In the signature, the data type is concrete.
- 0:51
The add function takes only ints. Now take a look at the definition of the sort function. There are two key differences. First, there's no concrete data type. Instead, A is the type variable, which can be substituted with any data type. Second, the typeclass ord is specified as a type constraint.
- 1:10
This means that A represents any data type that belongs to the ord typeclass. Or, in other words, a data type that can be ordered. Going back to the add function signature, if we remove the signature statement, the compiler makes an inference for the combination of type constraints and type variables as shown here.
- 1:27
The type constraint is additive, which means any data type that can be added. Let's look at some more examples of type constraints and variables. The first example here is the map function. The signature shows the use of two variable types, A and B.
- 1:43
The expression inside parenthesis with the right arrow between A and B denotes the function that maps A to B. The function is the first argument. The second argument is a list of type A. The map function applies the function to every element in A and returns a list of type B. Our second example is foldl.
- 2:02
If you recall, foldl takes a function, an initial value of the accumulator, and a list. It starts with the accumulator, applies the function to each element in the list, accumulates the result in the accumulator, and returns a result in the summary value.
- 2:17
The function signature has a type constraint foldable, which means it constrains the data type T to be something that can be folded to a summary value. Given these notations, let's define our own parametize function using type variables and type constraints.
- 2:33
In this Hello function, the signature says that it takes a type A, that must be an instance of the show typeclass. That's the type constraint. The function takes an input of type A and returns something of type Text. So this signature has a combination of a type variable A and a concrete type Text.
- 2:51
The function definition takes an input of type A, converts it to text, and prepends the string hello to it. Then in the script below you can see that the function is able to take an int, a list, and a tuple, and is able to return the expected result.
- 3:05
All these data types; int, list, and tuple are instances of the show type. Another data type to mention here is the optional data type. The optional data type is different from others because it's ambiguous in nature. This data type is used when a variable may either hold a specific value or may not hold anything. Let's think of a box of chocolates. The box can hold chocolates.
- 3:29
If there are chocolates in the box and you open the box, you'll see chocolates. However, if there's nothing in there, what do you see? Well, nothing. That's what this data type defines. Its generic definition as shown here, shows that optional A can be either none or Some A using optional as an indication that at times it may hold nothing and in those cases we need to handle it properly.
- 3:52
None comes closest to what null represents in other languages as Daml does not have a true null. So how does this help? Let's take an example of the problem of division by zero. If you write a function that divides X by Y, your program will throw an arithmetic exception if Y is zero. So you can define a safe division function the way shown here.
- 4:14
Its signature has the return values optional int. In this definition, the first pattern match has divided as underscore, indicating a catchall and divisor as zero. In this case, the function will return none. Or, as per the second pattern match, it'll return some value of type N.
- 4:33
The optional data type is commonly used to represent errors explicitly and avoid raising exceptions; where from the business logic perspective, it makes more sense to recover from the error than to abort. So let's go over what we've covered. Type variables are used when we wanna write functions or data structures that can take a wide range of types.
- 4:54
Often we need to constrain the range of data types using type classes. For example, we may want a function that can take different types of values. The values should be of types that can be ordered, or we should be able to fold the values into a summary value.
- 5:07
Type constraints help us specify the special requirements that the data type must fulfill to be able to replace the type variable. Finally, optional data types give us a way to deal with functions that may otherwise result in an error condition.