 So Haskell's known primarily for its type system, right? What's the type system doing for us? We're going to get some making mistakes however We can't do that. We don't get that benefit unless we explain To the Haskell type system. What exactly our domain is? If we don't tell Haskell what our data should look like it can't help us. It's not psychic, right? So often when I'm working on a project, I Don't start by writing functions. I start by writing data types So I'm not even really writing code. I'm just writing my types And I'm doing this because I'm trying to basically write a spec of what it is. I want to work with I Want to know what problem I'm solving before I try to write solutions to the problem The data types in Haskell are often described as algebraic data types Algebra is a scary word for some people. It's not too big of a deal. Basically set of operations Over some domain. So in this case what algebraic data types in Haskell means is that we have a couple different operations and Some glue to put everything together and I'll show you what that looks like But first we're going to go over some syntax because it's programming. We can't go anywhere without syntax, right? Alright, so the simplest possible data type you can define is trivial There's four different component. Well, I'm only marking off two, but there's four different syntactic elements here One is the data keyword on the far left That's how you begin the definition of a data type Data type the thing following the data keyword is your type constructor so in Haskell We have a separation between types, which is how we circumscribe and Talk about sets of values and I'll go into this more in a bit and We have terms which is our actual kind of code. That's our actual code that executes Those are our functions and our values In Haskell we can't really pretend types are values. We can't really generate types from that We don't have dependent types yet, but you know icebergs working on it The keyword here the key here is just remember that on the right-hand side. That's actual code So to demonstrate that point I'm going to pop it in my repl here data trivial equals Now one thing that's a little bit confusing here is our data constructor and types instructor have the same name This is a common idiom in Haskell a little bit troubling for beginners though Because they can't tell which is which or what goes where Right, so what I did here was I defined the data type and then I queried the type of a value I Can make this a little more explicit? I could do that now. They have different names. Oh, you know what? Let me Yeah, all right so There's no such value named trivial Because it's not a value. It's a type constructor the type constructor So we have this value here. Well, we don't have show we can fix that So the value doesn't really do anything. It doesn't contain anything. It just stands for itself But if we look at the type If we ask ghi to tell us what the type of our value is That's where our type constructor comes up type constructor value value Yeah, it's um, it's syntax to assign or assert a type for a particular term or expression um, so you would use that to define the type of a hypothetical function This doesn't matter. That's not Correct hassle syntax. It's just it doesn't matter. It doesn't This is a example function though. The name of our function is f It takes two arguments of type string and then it returns a final string that colon colon That's how we assert a type for the function. If we didn't do that. It would just infer the type for us Do hascours rely on that? Yeah, not so much for functions top of the functions Of those three screens. Which one is the return type? That's a really good question So, uh, I lied to you when it said it took two arguments There are not two arguments here Sorry for lying Because of curry all functions in hascular unary. They take one argument and return run result But we know we're going to write functions that take more than one argument That's something we want to do Right, so how do we model that? Well instead of multiple arguments We have multiple functions What you're seeing here is a function. That's actually two functions When I was talking about type constructors a moment ago Those are actually type constructors as well. They're just in fix and baked into the language That's the type constructor for a unary function How many of those type constructors are there two? That's how we handle two arguments two unary functions. So It's right associative So the first function Is a function from string To string to string So our first function returns another function that accepts the next argument And then when you run out of your little arrows, then you get the final result after applying out all the function arrows Yeah, yeah, that's exactly right Well, I mean it's it's the you know kind of nominal return type, right technically there's an intermediate return type I can demonstrate this point Really quickly. So if I just have let f string String string And then I do f x y so I'm taking two arguments x and y there, right? And then I can just ignore the arguments and do blah Okay, and then if I do f blah It just returns a constant value, right? Okay, but under the hood Under the hood. This is actually So we nest two lambdas and those nested lambdas Are actually how it you know works under the hood This is the anonymous lambda syntax in Haskell You can use multiple argument syntax in the lambdas as well. I didn't hear for the sake of demonstration So when you have a two argument function under the hood you actually have a two function object And then what we can do As a result of this is we can partially apply it so Let's make it actually do something with its arguments. I'm just going to say x and y equals Law concat x Okay So if I just apply this to So this is the string concatenation Function, this is how we just blew two string values together And I applied both arguments and I got a final string result. However, what I can do Is I can actually define an intermediate partially applied function I can drop this argument Now we lost a function error Why because we applied one of them away Right, so now that x Is always bound for this function to pop Yeah, you can and in fact sometimes you'll define functions in An eta reduced form where you just you have implicit arguments. You're not bothering refer to because they don't matter um We aren't going to explain that today. Sorry, but Suffice to say yes You one thing to be aware of though is that there isn't a show instance Which is how we're getting like these Gici can print values that we the results of our expressions because of an interface called show type class uh The function type doesn't have a show instance um I don't think now is really the time replaced to explain why a show instance doesn't really make sense for functions But suffice to say if you try to just you know hit enter with only one argument applied You still have a function object in there. It's going to complain So That's why I did the lead expression and went from there Okay, so All right, so Scooped my own slide, but the point here is before the equal sign Is your type constructor singular you're only ever going to have one type constructor After the equal sign those are your data constructors those are your actual values So you're going to use the type constructor after those colon colon The types and entries And you're going to use the data constructors in your actual terms and the things the part of your code that actually kind of You know does things We have phase separation as it's called in haskell so you can't freely intermingle types and terms and kinds and sorts and so on and so forth If you try to use a type instructor is going to say I don't know anything by that name in in terms space There's no value name that there's a type name that but there's not a value name that So If you wanted to learn how to do that You missed the address talk Okay, so let's write functions over trivial Well the proof is trivial There's nothing else you can do if you're returning trivial other than the trivial data constructor Nothing else will type check. I know this seems absurd but bear with me um The point here is simply that if you have a value of type trivial, so this isn't even a function this first one The proof is trivial. It's not a function Why isn't it a function? no error There's no function object here. We're not taking any arguments all right Is the second one a function? Okay, how many functions are there? Perfect Because it's one function error all right um And I mean so we actually explicitly match on the trivial data constructor here But there's only one possibility because there's only one data constructor in the data type So there's no real point. We can just tell haskell. We don't care anything No matter what you give us we're going to return trivial Because there's nothing else we can return. There's nothing else we can do That's it Or you could do an irrefutable binding where you're not specifying a data constructor, but you're giving it a name We could go over that later. You're not even really going to be writing functions today Okay So this little interactive bit feel free to speak up. In fact, please speak up All right, can anybody raise their hands? And tell me what they think this function can and cannot do. Yeah Okay, that's good. That's you're right so far. There's something specific I want you to tell me about what this function can and cannot do I want to expect you to read my mind Sorry, yeah Well, yes, you're you're on the right track. I maybe I'm being a little too picky, but yeah Yeah Yeah, so you're riffing off what he said. That's good. That's good. Okay, you've got it. All right So the point here is that this is Effectively the same As a constant value It serves no purpose There's no reason to have a function here Think about it. If there's only one data constructor If there's only one value We can only return the same result every time it gets applied Which means that this is equivalent to just a plain old integer value It's just forcing us to apply an argument that doesn't matter Now the reason I'm talking about this I know this seems silly But the reason I'm talking about this is I want you To start thinking about your code in terms of domain and codomain domains the set of values your function accepts as an input Codomain is a set of values. It returns as a result This function is really easy to reason about in a sense The integer return type is kind of big. It's actually infinitely big But if we ignore that it's actually really simple because there's only one value that it can have as an input So there's only one behavior It can have it cannot vary its behavior because there are no other values Yeah All right You don't Can Because you would have to emit i o in order to get a random integer Functions in haskell are actually functions. So you can't perform side effects without saying so I'm saying the actually function part because a function that returns a different result for the same inputs isn't really a function It's a procedure. I know what I said had a lot packed in there. So I'll reiterate This is purity that I just talked about in haskell. Everybody says it's a pure functional part This is purity same inputs same result I cannot Get a random integer I can't be just returning a random integer. It will always return the same result now It could be an arbitrary result, which you highlighted. It's good. It could be any integer But it'll be the same integer for all inputs Because there's only one input anyway It never changed Now I'll show you an implementation. Thank you for bringing that up We defined trivial uh previously and This there's only one trivial, right? Yep. So there's only one input Yep, that's precisely right Any type gems we could change the value of returns the integer returns, but it's going to be constant So for our purposes this could have just been integer no function No difference I'm sorry, yeah, um, I Sorry, there's not a lot of stuff about functions and pattern matching because I didn't actually plan to talk about functions Um, I was going to try to keep it to just like data types because I just be purely declarative. You don't have to But okay, I'll explain it. Um, so I'm pattern matching In a sense, I'm kind of dispatching or matching on the trivial value I don't have to do that though I could also just say I don't care what input you give me Or I could say X and then you know Yeah, um, but I can't do anything with it like it It doesn't signal any information Can anybody tell me why having one input doesn't signal any information? Right. There's only one value. Now if you had a list of trivial You could maybe make an esoteric Turing tar pit out of it But you need a list first if you have just a single unary value With only one possible bit of information Actually, not even a bit of information. Sorry. Yeah, there's no there's no true or false here. There's no zero or one You have no ability to encode anything meaningful here Um Turns out trivial already exists in Haskell It's just called unit That's it So if you ever see a function that returns i o unit. Yeah Yes, yes, and in fact Um, I don't actually need the type signature I could just define it like this Now it's going to infer a slightly different type Um So well, okay, it doesn't know it's trivial hold on now you're going to see a little bit about a type inference Okay, so it didn't know what type t was It didn't know what type t was Until we pattern matched on it because if I just say x it could be anything, right? And if I don't assert it in the type signature, it doesn't have enough information to know what type i'm talking about But it also knows That i'm going from type t to a and a is some some number. That's how you can read that Um, that's a type class constraint Again didn't plan to talk about those today um, but yeah, it's uh You can just define it like that and then as soon as I pattern match on it It knows what data constructor i'm matching on then it knows what type I'm accepting as an argument Okay, so what we saw with trivial Is what's called a nullary data constructor Trivial doesn't nullary data constructor. Does anybody know what arity means? number of arguments Trivial doesn't take any arguments null zero arguments No arguments So it's the simplest kind of data constructor you can have it doesn't contain any other information other than itself As a value that you can pattern match on so what's the next step? What's what's bigger than zero? One unary data constructor So we have identity Now we have a type constructor and a data constructor that takes a single argument They both have to take this argument And they have to agree There are ways to get around this But this isn't intermediate haskell so we're not going to talk about that attends. That's impossible Because for your purposes for now it is So we have to refer To that argument In the data constructor and the type constructor equally But there is an exception here And i'll show you all right, so That's fine, and then I could just put stuff in it What kind of stuff? any stuff Any a Anything whatever you want We could put trivial there if we wanted still wouldn't signal anything meaningful But we good All right, so let's try to break it So by default The way we introduce type variables because that's what this a is It's a variable that could refer to any type The way we introduce type variables Is in the type constructor if we didn't introduce the type variable We're not allowed to use it You can do existential encodings to introduce the the type variable elsewhere. I'm not going to teach you that Don't worry about it Now What if I flip it around? What if I have a type variable in the type constructor? But I don't use it in the data constructor raise your hand if you think that won't work Raise your hand if you think it will work Oh, we got a split house. All right About half of you are going to be wrong Works fine It's called a phantom type Now this is actually considered an intermediate kind of tactic For making your house code enforce what you want But the reason i'm showing you this is because I want you to understand something the concept of a witness When I have that function This function and list of cars to string That's all just a list of characters Okay, so How does it know my argument is trivial? Because a pattern matched on it, right? This value here that we're matching on this is a witness To the fact that our argument is of this type You're going to hear the word witness used a lot by some really smart people It helps to know what they're talking about. I spent maybe like the first Three months learning hassle trying to figure out what the heck witness meant Uh, it turns out it's actually a pretty simple concept. Just nobody ever defines it because it's simple so With a phantom data type Well a phantom type argument I should say really What we have here Is an a that has no witness It doesn't occur anywhere in the data type in the data constructors. I should say So It just never gets used you can't use it to enforce things But there's no link to terms. It only happens at the type level It this tactics actually really quite useful. How many of you have ever worked on a web app? Oh, yeah, okay, and how many of you have forgotten to escape something I I have come on. Don't lie. All right So we can use phantom types to do things like track state transitions that we don't have a meaningful value for There's no value But we just want to be able to say the type went from not escaped to escape Then we can enforce that nothing goes out the door unless it's been escaped It's really nice Just with type Okay, what can we do with this? We can unpack it. We can pattern match. Yep Sorry, so you gave me a sample of what a witness is And you said nobody defines it Is it Did you could did you actually state it at the mission? Uh, not really Fair enough. No, no, no, it's fair I'm sorry, I did not mean to So, no, no, it's fine. So basically type inference in Haskell is actually it's It's complicated in a sense, but you can understand the gist of the behavior if you just think about how When you do type checking you're starting with a type and then you're making certain the terms don't do anything that violates the type With type inference. You're kind of working bottom up So bottom up here would be we pattern match on this constructor So it knows that this argument is trivial It's able to then make the connection that if this is trivial Then this argument has to be trivial and That that's it's a witness to the fact this value is a witness to the fact that you're type For this argument is trivial It doesn't well, okay The word known here is kind of Imprecise, but you're right. It doesn't have to be concrete actually um Do you remember when we had x? So Now it's just like it's just a type variable Um, it's universally quantified not that anybody know what that is right now, but that's fine Um, but yeah, it's just like any type t anything in the universe list of car and actually This actually communicates the same thing as our trivial type, but for different reasons We don't know anything about this type right? We don't know what type it could be So what can we do with it? Nothing So it's still a constant function Nothing changed There's only one thing we can do with a fully polymorphic type like that where it could be strictly anything And this is actually another thing. I want you to understand there is an inverse relationship between the generality of your terms and your types The more general your types are The more constrained your terms are The more specific your type is the more things you can do with it I can give you an example So we have the identity function, right? That's a to a that's any any a And a means the same thing throughout So if a here isn't then a here isn't Okay, or a number sorry inches short for integer so The identity function isn't allowed to know anything about your input this is Related to parametricity, which I think there's actually going to be a talk on later So if you want to learn more about that Check out the parametricity talk at least I think there's a parametricity talk could be wrong. Sorry um So if the type could be strictly anything You can do strictly nothing with it other than just kind of pass it around so The implementation of identity is just id x equals s We're not matching how to kick our constructor. It's just a variable. It could be anything and we're just kicking it back out And that's all it can do That's it. There's only one implementation for that type There's only one valid function with that type This is extremely helpful because if you're working on something that's a bit challenging It can help to define the function that you want Use parametricity to kind of Get rid of the parts and things you don't care about and you don't want to do And then you're basically railroaded into writing the correct function based on your type But I've done it both ways sometimes I start with terms sometimes I start with types It all depends on the situation Okay, so a little bit more pattern matching and stuff So the first one unpack we go from a value of type identity a to a What do we know about a here? Nothing just it could be anything So we can't do anything with it But we do know one thing our a Is packed inside the data constructor identity So we know we can just pluck it out of the Well, you think it was like a box if you want you're plucking a value out of a box That analogy falls apart with some more advanced stuff, but it's fine for now So oh we could take it out, right? But we can't just take things out of a box We can put them in a box Right So we can embed There's actually another name for this return or peer You're not going to learn that today either or not for me anyway. Sorry You you will learn applicative and monad eventually don't worry about it Um, okay, so we can put an a and we just pass it as an argument to our data constructor identity And that's That's all we have to do Again This is the data constructor This is the type constructor. They could have different names. My apologies for following the usual kind of Haskell trope here but Yeah, data constructor type constructor. Okay, and then we also have Yes, it's going to be a little bit rough. Um, okay, so this is a higher order function It's a function whose arguments Include also a function Now we have to use parentheses to express this Because otherwise it just looks like two arguments right Because if we didn't have those parentheses it would look like you were taking Two arguments a and b The parentheses is how we express this is a single function value that we're taking as an argument And then all we're doing is mapping over the identity data constructor We're just applying f to whatever it was So show you The significance of that Now I know some of you've already seen the type But I want you to try to reason Through what this does based on the type. Yep See this is why I need a type system Because I'm a goof. All right. So we have a function that takes an a and returns b So we can take that as an argument We take a second argument Or a second function if you want to be precise, right? Everything technically takes One argument one result We have an identity a and then we get an identity b All right. Well, we know a few things we can pattern match an order. Sorry Let me talk. Sorry. Okay We know we can pattern match on the identity type constructor Sorry data constructor Gotta be careful We can pattern match on the identity data constructor and we can get the a out of it, right? So we have an a All right, how do we get from a to b? So that we get our identity b Yes, we apply the function to the value Because we don't know anything about a What do we know about b? It could be strictly anything B could but it's also allowed to be a different type than a doesn't have to be But it's allowed to be That's another thing that I missed when I was first learning Haskell I thought a and b had to be different types. No, no, no, they're allowed to be now if I had a function A to a they they would have to stay the same type But that's less general And there's no real reason to write a function like that that only goes from a to a Because we do the same things It's the same function All right So our only way of getting a b because we don't know anything about a or b So all we're allowed to do is apply a function to get a value of type b Okay, we have a value of type b. What's the last thing we need to do? Put it inside the identity data constructor so identity and then because of Syntax we have to parenthesize it And it works All right, so what's an example of a function? Well our little plus one here That's a function It stays in the same type It just goes a to a you know that a is a number. So that's not actually strictly anything Instead, it's strictly anything that can be used like a number and This suffices for our e to b Now we can use ink With number values that works fine But we can't The moment it's an identity data constructor Now this is one of the type errors That really confuses new people and I sympathize Does anybody know what this is telling you? I'm actually curious like Yeah, now here's the problem some new people will actually like They'll go and try to implement num. Don't do that It's not what you're supposed to do. That's not your problem here So, uh, this is like the You know You tell the new guy to get headlight fluid and he ends up climbing killman jarrow to find headlight fluid. Don't do that um The air is lying to you Sorry The air sucks and a lot of new people run into it because what else are you going to do when you're first learning a language? Other than use numbers and strings, right? So Kind of regrettable. No, here's here's the problem We have a num. We just need to map over our identity constructor We just need to you know, ignore it basically Yeah Oh, I see I see Uh, yeah, so There is actually a reason this data type exists It is conventionally called identity It is probably not precisely Meaningful to call it identity. So you actually have a point there, but it is conventionally called that um The purpose it serves Is to act as a kind of a null op for some higher level interfaces that you'll learn later So basically if you have a functor applicative or monad And you're combining some types you're combining their functor applicative and monad instances But you don't actually want to do you don't want a particular behavior. You just want to map over the The constructor this is basically a way to get up. It's basically a way to get an a That is of kind started. I I can't really explain this properly without going to kinds Um, it's a way to get out like a higher kind of a that doesn't actually do anything Yeah So So let me let me reiterate what you just said so everybody can hear um So sometimes you don't really want your types to just say like, you know integer string string string string string If I have a function from string string string string to io unit, how do you know what I just did? You could read the function I guess but the type's not going to tell you much, right? So sometimes we create we actually use new type for this Um, but sometimes we create basically like little wrapper types And new type is specifically restricted to this kind of type Um, and basically it's just a way to have like, okay One of these is a host name So we're going to create a little data host name Equals host name integer or sorry string And then if you have a port you do a little data port equals port and then that's you know an integer whatever type you you know You want to use for representing a port number? That's what your type instead of reading like string string string. It says like, you know host name server name things like that um, but that's not actually why identity specifically exists Identity exists because again, you want to just have like a pass through Constructor for some higher end interfaces that you'll learn later It's just a pass through entity Kind of like an LLC, uh, okay, so Yep, we've already uh demonstrated that And we've already talked about how we're not going to talk about it Okay, so What's bigger than one? Okay, you're right in principle But I just wanted this success. Yes, too. Okay All right, what what happens when we get to two What what big change happens If we have if let's say hypothetically we have two data constructors. What can we do now? Oh, I said two data constructors Sorry, you've actually you're right. I'm wrong. Sorry if we have two arguments to a data constructor Now we can now we can carry around multiple values Right, so this is a product. Uh, how many of you know what a struct is? Record Class ish ish Yeah, okay, so we're just you know We're carrying on a basket of multiple values That's all so to move from unary to product We just need a couple more type arguments So our data constructors are values But another thing that often confuses people is that this is a value This is a type constructor But these are actually also type constructors The arguments to your product your data constructor are themselves types So you can't say like person of one in blah You have to say instant string. You can't specify a particular type or value. Sorry. Yes Yes, it is a single data constructor that takes two arguments The first argument is string and the second argument is in So previously we we went from We went from a constant value With the nullary constructor With the unary constructor we went to a function of one argument With product we're now getting into multiple arguments So if we define this Actually here, let me just do it nullary first Just a value One argument Two arguments Three arguments See how it's stacking up Now what's important here is that The way a product works is it saying you don't get to have a person value? You don't get to have a type a value this type Until you give me at least A string and it's in a string If you only have string and an int You know person yet need the last string Yes, this is a data type and when you define your data constructor In here the moment you start adding arguments to your data constructor that becomes a function automatically Yeah, so that's actually another thing when you hear the word constructor function Constructors take arguments now I was referring to type constructors earlier that didn't take arguments That's not precisely correct, but that is how people conventionally refer to it If you want to be precise what the haskell report actually says Is you have type constants And type constructors string is a type constant String doesn't take any arguments So it's actually a constant just like you know our trivial data constructor was right So, yeah constructor function So if we have a type constructor We have a type function Yeah, and and they they they had it earlier. Um, I flubbed I I said multiple data constructors, uh, kind of accident. I've said it more than once but Specifically I said it in a moment ago accidentally when I meant multiple arguments for a single data constructor So, uh, that's a sum we'll go into that in a moment. Yeah So most languages have products. That's not really anything too interesting Um, sums are where we get into the realm of kind of a smaller community of programming languages We can also use uh records in tax With our product. This is basically the same as The one that just had arguments But we're giving names to the arguments You don't use these when you're well, you could you could actually use record definition syntax. I'm not going to go into that Um, but mostly these are just accessors Like if any of you have ever used a language with classes And you ever used like a property of your accessor You know object dot something It's kind of like that, but you don't use dot here. It's uh, they're just functions And actually here. Let's have a little bit fun with this. Uh, okay So i'm kind of giving the answer right here, but If I ask for the type of age What do we think the type will be? Anybody want to guess that's precisely right age is a function from person to int So you're just pulling data back out of the product um record I'm mentioning records in tax because You just have like two values in your product Doesn't really matter not too compelling. Maybe for like a little bit of extra documentation If you have a product with I don't know 100 fields Maybe you don't want to pattern match on those manually Just suggesting yeah Just for clarification about the language Yeah It's it's the same type so it's still two arguments Yeah, and if I add like a third, you know field There it's it's just going to attack another argument So it's and you can use it in the same ways as the non record syntax You just take a function you apply arguments and then you get a value it's it's You can use the record syntax for a few different things you could use it for Uh replacing values I'm not going to say modify because that implies mutation is occurring. It is not you're constructing a new record with that one value being different um Or you can use it to just extract or pluck a value out so To give you a quick idea of what that looks like And it uses record syntax because I used record syntax If I didn't it wouldn't because I wouldn't know what to call them anyway It looks like what you typed here is different from what was on the slide and your typed definition Is it? Nope, I'm wrong Slides are wrong. Sorry Sorry Yeah, so the equals that's the record assignment syntax I mentioned earlier Sorry, sorry. Sorry. That's the right way to do it You got me Okay, so, uh, we have our And then Actually, I'll use parentheses because I haven't explained dollar sign yet Okay, so if I do that, what is it going to return? Bapu And if I do that terms age and he's about that Um, you can define like accessors yourself If you want there's no real point. It's really just like getting equals name. It doesn't mean anything Interesting Yeah, I am I could also here, you know what I'll just do like a quick I'll do it with pattern matching So if I do that and then All right, so it inferred the type How does it know it's person to string? Yep Because this is basically just an alias for that field access or the Records and tax introduced. We don't have to be that quite that redundant. We could also just pattern match and then say person and then Name we don't care about age And then Yeah, exactly. Yeah, and then I can use get name person papu I just really not use a person because I hear you ask but Yeah, no problem. Thanks for asking It's uh Just about noon. Um thought I'd give everybody a quick break That sound good All right, so we had Anonymous lambdas. What if we want an anonymous product? Lambdas, you know function. I know I haven't explained the lambda calculus or anything But if you just replace the word function in for lambda That works just go with that for now. All right, so Uh, first we're using a different keyword now We're using the type keyword The type keyword Basically creates type aliases It creates a new name a new Type constructor although this is technically a type constant, right? For Stuff that you already have Data constructors and type constructors for so in this case We're using our tuples in tax to refer to a tuple that contains two values It carries two values around just like our person did but it's anonymous Our tuple here doesn't say anything about person It's just tuple string int right That stuff existed before we define this alias That just exists already. It's already defined In the base library for haskell for ghc. I should say So When you use a type alias when you use the type keyword you're creating a type constructor You're not creating any data constructors so Here's an example tuple two values we can Petter match on it so we can pattern match on it do stuff Return values back in or we could take them out. We could have just plucked one value and return that as well All right, so This is Okay, so the type infer here is a little bit gnarly We're saying it's okay list of car. Remember I said list of car is actually string Guess how string is defined type string equals list of car It's just an alias. The problem is the inference doesn't use aliases Because you can define multiple names for the same type How would it know which one to use there's been some suggestions that they would work on that? I don't know if it happened if we define a person type alias like this We can assert That's a person And that works It doesn't complain no errors I'm sorry if we see any people where you're going to go for I remember that I've I've been trying to avoid it um partly because we're Uh, I don't know if we're going to get to the final exercise or not, but um, so okay, that's It's not uh greater than or equals um, it's the type class constraint And basically it's all right. So you remember how if we had like just an a by itself It could be strictly anything So that's what's called parametrically polymorphic just anything at all all right We still have a type variable here this t But this can no longer be strictly anything What does t have to have or do? Right, we need to have an instance of the num type class Flight class is an abstract interface that lets you use the same terms across a set of types But what did I say about types and terms? The inverse relationship when we move from a parametrically polymorphic strictly anything type variable to one that you could call a type class constraint We could call it ad hoc polymorphic although that'll make some people angry. I don't really care um Where our type space is shrinking? right Because num t Not every type in the universe implements num So that refers to fewer types Than just you know a t or an a standing by itself But what do we say about the inverse relationship between types and terms if our types shrunk? What happened to our terms? We have things we can do now we can do stuff with it now Because it's num instead of only being able to just kind of kick the value back out Which is all you can really do with a parametrically polymorphic value or you can apply functions to it technically, but that's Effectively the same as just passing it around Um now we can use stuff in the num type class You can use the colon info command in gi to look up info So when we say a type Has an instance of num. We are saying it is equipped with an addition operation multiplication subtraction negation absolute Sign Signum, I don't know and from integer. So we've got a general way to convert from an integer value to just any num in the universe okay, so And we look at the type of our addition function It takes two a's and returns one a Does that make sense you add two things there you get one thing back right Now they have to be the same a all throughout A can't stop being a Because it's bound. It's because of binding again. I can't explain this right now, but A's bound all the way over here. So it's just the same a throughout um Okay, but we can use plus with anything We don't need like a plus in plus float plus integer plus rational plus plus You don't have to do that In Haskell we have a polymorphic What's called a numeric tower? It just means you have like a set of operations and there's So num's kind of the base type class. There's stuff that's specific to integral numbers stuff specific to floating numbers things like that Okay, so that's how we create type this is so Tuples are the anonymous product What does that mean for us? Well One of the nice things is we can nest Tuples two tuples. We need at least two Otherwise, we don't really have anything in the nest now We can represent A product of any number of arguments as long as we have at least two Remember trivial Same information theoretic issue you need at least two to be able to do things with it Okay So in some sense the two tuple the tuple that takes two arguments Is the anonymous universal product? Now Let's say we have this data type. Hey, I didn't use equals this time. Cool. All right, so Got it right I promise you I can write Haskell code. All right, so Um, we have a card data type here It has a make a model in a year All right, so real quick The worksheet it should have this at the top of the worksheet. Everybody's a worksheet, right? All right This is everybody I didn't bring pens people have pens right with Okay, if you don't have a pen try to get one from your neighbor Uh Do it in your head if you don't have a pen. Sorry I should have got like a big bucket of big pens Oh, yeah, you can do the raffle if you want Yeah, go for it. Yeah, if you have the raffles go ahead Do it in there. It doesn't matter Oh, and I know I haven't defined the car make car model car year data types Doesn't matter you can make them trivial just data car year equals car year What those are doesn't matter for this exercise You can either not bother to define them and just ignore the errors Or you can if you're using repel or you can just define trivial data types for them It's up to you On I would personally just do it on one line because it's not it shouldn't be that long but you can try that Don't worry too much about syntax. I just want you to have the idea in your head All right. Does anybody have an answer written down yet that I can look at No victims. Okay I'll wait I can wait Are people getting answers now? All right, what am I writing? Here, I'll I'll fix that Okay Here yep Yep, there we go. Do you got it? You've got it Like Okay, so I was being a little bit cruel I intentionally I showed you an example But I went through it quickly on purpose because I kind of wanted you to try to figure it out Now I can explain the syntax now so All right, you remember what we said about function arrows and figuring out how many functions there are in a type signature Okay, so the actual unapplied Tuple type constructor is that and then it has arguments a and b which you can then in line Okay What can a be what can b be? Do they have to be the same type? Can b be a tuple? Can that tuple contain a little tuple? Can that tuple contain another tuple? Cool. That's it. We just have two nested Tuples Well, you lose the record accessors that much is different however when we think about our types in terms of domain What values can be represented? Is there anything that this data type can represent that our tuples cannot? Are there any values we can construct that aren't interchangeable to and so? So I'm using the word product What's product? You can partially So it's still a function, right? But if I apply Second argument Okay, so real quick. Let's let's talk about why these are equivalent That's a good question What's product? Why am I using the word product anybody guess? Be brave. Yes, it's multiple armists, but it's also multiplication Okay, yeah so Really when we say we have a product of Helps with my fingers actually on the touchpad We're saying car make times car metal times car here How many how many values are there in each of those data types with the little trivial data types? One what's one times one? What's one times one times one? How many values can card be? How many values can that tuple I showed you be? Perfectly equivalent. It's just syntax So Yes, but they would technically be different even though it's not in a you know informationally meaningful way Yeah, so the order matters for the argument application order, but it doesn't change anything here It's a good question. Okay a couple more exercises We have these two generic functions over Two tuples first and second first it's The first value second gets the second value I want you to write so we're getting back to what you said with the record accessors. We're going to get our record accessors back For that type alias by defining themselves ourselves manually So go ahead and define the trivial versions of car make model year Define the type alias And then see if you can write these functions the way Just so for the people with ghci So the way I would set that up. Oh, it's history. He's not going to help me. Okay. I see how it is The order I define the data types themselves in doesn't matter Whoops, so like that if you have a ripple up. Yeah Uh I haven't actually introduced composition. So I'm not certain What you're asking what do you mean by compose? I'm sorry Oh, so the uh Function application binds the tightest So that's not an infix operator So you remember you remember how I had to do identity f a with parentheses That's because otherwise It tries to just like apply it as one. Well, actually, you know what? Let me check I think it just tries to apply it as one block, but So it thinks you're trying to apply identity to our Because it just goes left to right tries to Apply the identity constructor to both arguments So in order to refer to this one argument Which then gets reduced or evaluated separately Use the parentheses around first and second already defined or we have to We're already defined. Okay. Yep. They're in base Pretty So they should already be in scope. You shouldn't have to importantly We're doing this by doing the Uh, yeah, so use the type alias for use than as a tuple. Um, I would just use the trivial Data types or make a lot of them here that I use because again, they don't really matter here And then yeah, you're trying to figure out how to combine first and second Uh, I one quick note because this may actually Go off so that you don't try to I mean it. Well, okay You couldn't write this in a data reduced form. It doesn't refer to the argument But you can introduce an argument to refer to your car value if you want There's a couple different ways you can write this. I'm kind of trying to push you towards the Data reduced form by telling you to use first and second But technically use a pattern match to get these accesses So there's more than one way to do it. I'm just pushing a different direction By suggesting we use first and second In fact, do the first and second version. I'll do the pattern matching version right All right, so that works. I just pattern match. I actually I'm matching up the second tussles. I don't actually need to I can just point that out And that still works Now what happens If I try to return A different value what if I mix it up with model? What do we think is going to happen? Well, somebody said it would be an error We get a tyker Because it knows because we refer to the type Carburet It knows that part of the tuple that part of the tuple isn't a car make but If we say we need to return model There you go We say it's model and it works Then we can do here And that works All right, just go ahead and raise your hands All right using first and second. How do I write bank? perfect All right, how do I write model? Well, which one gets applied first? There we go. Yeah, you're right It's in task but it's first and second but Second implies first thing because you're going right and then left Okay, year should be pretty easy then, right? Second second So right, right Sometimes all right Choice somebody mentioned that earlier All right. So before we add multiple arguments One data constructor multiple arguments one data constructor is a product Now we go right on this part when we have multiple data constructors we have a subtype What summation? What's another word for summation? Add it All right We have two Nullary data constructors How many values is false? How many values is true? What does something do? To go right how many values can bull represent? To because it's gonna be false or true And that's actually another thing. So you think of product as being like conjunction or and Some types addition Is like or you can read that pipe there You need to replace that with or in your head. So we're saying a boolean value Is either false or true? Should make sense If not, I failed. Sorry Um, okay So we have multiple data constructors now This is the part where we start getting away a little bit from what most languages have And all derivatives have this Some new languages like switch kind of have this I don't think they have higher kind of types, but I think they have like a tag for me um All right We have an anonymous sum type too You remember how the identity A equals identity A? We're just tacking on another argument And we have an or. So we have two data constructors Why do we need two data constructors with two different type arguments for this to be being on the sum type? Tuple was tuple of A and B, right? And tuple's product so the tan of A and B either is or of A and B So you can recognize some of the universe. That's the either value. I don't know what you're going to do that What can? What's the meaning of the left and right kind of reasoning? Why do we need to name them? Uh, well you need to be able to refer to them differently So in this case we have Two data constructors. One is named left The other is named right And if you have an either You have A value That So let's say all right. We have either a B So let's make our uh I'm just gonna say B and then let's let's make it something specific like string and I'm starting using string and numbers stuff over and over but Yeah, you know what here, let's use we have karmic problem. Let's do that All right We either yes, but B Or A those will be another either right? Do you see the same nasty in the other? All right, so How many inhabitants? How many values? Can this type have two All right So when I apply this value, how many different ways could I apply it? Two two No, it's your question here All right, so If I have so remember that our data constructor for A is left and our data constructor for B is right So Which are just already defined Yeah, I'm a certain I'm asserting that the A is karmic and B is karmic model here So if I have left What must I have in the left data constructor? And if there was a right So this will work that would work Because we said if we have a left A So, yeah, but let me bring the data type definition So we said that if we give you a left It has to contain the A the first type argument the type constructor If we give you a right it has to contain the B the second and final type variable and argument to the either type constructor So an A is karmic and we have left A A has to equal A I mean, unless everybody wants to debate it equals A I don't think I'm going to put it for that. I don't know what you mean, I'm sorry so All right, but we're gonna we're gonna take that axiomagnetic. How does that A equals A and B equals B All right, so We don't have to create a new data type to define bold because we have you know in the subtype we could hypothetically If we felt in a fame mood to find it like this It was a lot like the tuple, right? Just a type alias either falls true I'm not going to show you this works Because you can just assume it works. Yeah Well, yeah, so actually everything I've been showing you Has been 80 t's in some sense We don't really have any t's And so we have at least two operations which are product and some So you just have products. You don't have algebra because there's really like only one Yeah, it's not really convention things being an outright data type So I think that types are you're able to express and as well as or And the algebra is the combination of and Yeah I'm sorry building block to Well, this is a Yeah, this is this is it The mysteries are going to be revealed I mean, there's more stuff. There's more eons. There's more patterns. I can go into kinds. I'm not going to But this is 80 t's products and sums That's it. There's generalized object data types and check out that ball. I will be I'll be good So, um, but that's I don't know like Yeah Okay, so yeah, uh, sorry to make that clear everything I've been showing you does get better types And the algebra is product and sum those are your operations over the universe. That's your structure And we're running out of time. Okay. You remember our trivial data here What was it equivalent to? Right. All right, how many different things can this function do? How do we know that? Right because our domain has two different inhabitants. So we can do two different things Okay So if you get it true It gives you one integer if you get it false because you're different integer And that's it Here functions. No, I have no randomness No launching meant to the moon while you get this supposed integer All right What about this one? How many different results can it return? Three because no area data constructors stand only for themselves. So they equal one And our little port is plus So it's one plus one plus one which is great. So quantum has three different values three different inhabitants And quantum danger it's able to return three different integers and that's Yes That's it. Can we change both to try? Yes Yes, you can you should more here in your code though seriously, um Yeah, so you can just pretend that that pipe Which is used in programming land kind of the or Any granaries for that matter actually like this stuff looks a lot like you do now You've ever seen one you can set it back to norform for like the final granaries pretty simple Okay, awesome. It's fine. Um, so Yeah And then here i'm just kind of showing you the outward, you know or is plus False here one and one two and half and this is the outro. That's it. It's all there is to it Here i'm just showing you that that type alias where we used to either define bull I'm just showing you that that's the same thing All we did was kind of define our type kind of all the card I'm not going to go into the contents of that paper but basically instead of defining a long pipe it contains False and true we find false and true as independent types with single values And then we glue them to the separate higher kind of that type like either Maybe my mind's somewhere else, but false and true about being one Well, so there's only how many okay, uh, so if we have like a trivial But for false How many now you know? That's it. That's all looking at this time. There's only one value um You've asked a good question But I don't know how to like put it into words It's I mean basically like do you have a value of type false prime here? Which is just that one data constructor. There's only one possible value So when we talk about the inhabit we're talking about types as if they were sets And we're talking about the sets as containing values. So here false prime is a set that contains one value Which is just the false one that Yes, that was the word I should have used thank you card now Type your sets Inhabit your card now If you only have one data constructor your card now leaves one is the set of one value Should have said something about that Okay What I'm trying to show you here is if you make it either A false and true your false and true singletons is the same thing same inhabit same Information being so technically they're different types, but it doesn't matter You're you're expressing the same idea Which is cool. Let's bring product back If we have bold To bowl at a topple Okay. Well topple product times Bull is two because it's single two single data constructors one plus one So it's one plus one parentheses times One plus one one plus one reduces to two two times two reduces to four inhabitants Now how can we improve this for ourselves? How could we prove to ourselves that this only asks for inhabitants? So, all right, what's the example of this type? We have false and false, right? I can have false and true I can have true and true I can have true and false And go to the circuit you can mention bottom doesn't matter. All right, four inhabitants module bottom We don't talk about bottom All right, so Four inhabitants four exercises um, we're getting Really close to it being time So here's what i'm going to do I'm going to talk about the final exercise for a little bit real quick Just so you can have a night because I don't know if the word sheet necessarily explains it super well But I'll talk about it a little bit and then we'll come back to this slide And if you want to ask questions about the final exercise or this exercise Please do something Oh and a quick like Don't do this This is from a paper on embedded code That people were actually using they're using it for like like race cars or something And they just like bolted it in a null, but as soon as like multiple problems here, um I'm gonna be back for a moment Like all right, if I have a null value, what happens if I use like one of those record accesses on? Yeah, it doesn't make sense There is no car length inside a null value. That's in the car data structure So first rule don't define your record accesses in the same data type definition As of some keep them separate. You just split them out into a separate data declaration Uh next thing you don't be null We already have a data type for that. Does anybody know the name of it? Right So if your car sorry didn't do the answer maybe maybe Yeah, I can show you the definitions for that one quick But the point here is that we have already abstracted out the idea the concept of not possibly not getting the results So you don't need to like bake in a one-off Gotten up constructed into every data You don't need to do that. We have already abstracted it out So if you if you have a function that possibly might not be able to return a sensible car Result for given input don't introduce a data structure like this There are hassle and they just they will find you They're on the way to these people right now If you can't return a sensible result return maybe of whatever you've got which is going to be maybe car and maybe It is kind of like either That's it. That's maybe All null exceptions. They don't exist Unless you come up, I'm not going to play with that. All right, so We don't have no errors because we're explicit about what we might not return a result The only difference between this and either is we have one less type variable and we have a null area data structure And this doesn't really tell you anything. So all it's really doing is telling you got Right, so you don't need to add a null constructor to every data type You just return maybe whatever the car we can't use here So is that just a description of nothing or just our actual types? Well, nothing. Okay, so I can actually just do an info on maybe here. So that's the actual definition of the type And maybe is our type constructor It's a some type of two data constructors. The first data constructor is nothing And it's a null layer data structures stand for itself And then the second data constructor is You name one arm. So it's not a product, but it's not a number either. So just Just says yep, we have a value of type A. We succeeded at whatever computation you're trying to do Nothing says we don't have a sensible value for those inputs And just basically just acts as a little box for an A value. That's all All right, so Yeah, there's the exception. There's an example. Please don't do that Yeah, there's Keep doing this to myself. Um, yeah, there's made so Oh, yeah, uh Just enough time Uh, be careful with strengths. Um You remember how to set the strings for a list of car? Okay, how big can a string be? Could be any Could be half there at the large What can a string contain? How many habitants are in strength? Hmm. Yeah Can you contain a thing in your head? I can So when you're working in strengths You get the full benefit of hassle if the hooves you to learn parts of common games And you get comfortable with using a real Custom but a real parser inside hassle to structure your data and then rejected valid inputs Don't try to do like the regents munging and stuff It's all right No pretend there's more structure in strength than there actually is right parser Having either result, you know Basically the way to think about it is like the parser is the only way you get the only way you get to escape String you don't get to stop having the string so you write parser That's the way to think about it. The only thing you're allowed to do is string so you've written the parser is printing That's it. So if you're printing it for humans or you're writing the parser Don't do anything else Effectively like the same applies for client strings. It's just like a string of binary data Same thing either just returning or sending it to somebody or your parser And don't use maps for products Maps are for like sparse data sets either record And okay, so um part of your worksheet Has an exercise in modeling human language Because they employ more inhabitants Well, they imply indefinite habitants indefinite inhabitants, and they also imply possibly no inhabitants The problem is is it's rarely the case that you know literally nothing about what's going to be in the product Usually you can structure and explain and describe at least some of your data So it's I mean like there's a compromise solution, right? Like you have something is guaranteed to be there And then something might not be there Now it's just like one field that might not be there. It's just me, right? But if you have like Users are inputting keys and don't know what the keys are going to be that kind of thing That's more like a mess. It's where you don't even know what like what the way to reckon something will be You have to have that the entire good side of it But if you know what the tides and the name and the da da da da da If you know all that up front and you're not going to have to slap like maybe I'm like Well, even if you have to slap maybe everything really implies you should break out some But yes, right apart try to Don't don't just like you about the news maps or anything because I've actually had people who like were in some Haskell But they came from an untyped programming language and they did everything with maps and they felt like the types it wasn't doing Well, yeah You have to like explain yourself to the types of stuff Okay, so the goal here is to get you to do a little bit of data modeling You're not really going to be writing any code in the conventional sense You're just writing data types And I'm not giving them to you You have an english language description of A partial explanation partial definition. We're not going to go into the maximum detail here of how verbs in english work You're going to need to use products and sums And you're going to need to nest these data types There's not the one right answer but there are better answers than others See if you get a verb upon the answer you arrive at So I'll give you one case your top level data type is probably just going to be verb Because that's what we're modeling and then a verb is going to have different kinds of things We're going to have transitivity We're going to have just go ahead and include the verb itself of the word You're going to have how they get conjugated And then in conjugations themselves We don't really have a lot of conjugation in english among latin So you have like past tense and past partial That's about it And then once you have a data type you think makes sense Try writing a super super simple little parser Not going to actually be a proper parsed commentary on this Don't attempt that right You kind of want to know what you're going to do Well you don't have to You want to do it Where you're going to do that Just write simple functions And see if you can take like simple subject verb object sentences And parse them automatically into your verb data type So in this case if you have such a function You have a couple of options here depends on how much work you want to put in One is you could normalize your swaps here Should just be infinitive or mathematical Of swaps Or you could leave them alone Up to you Whatever you want to do And then It has a subject, it has an object We have some examples Just in very practical terms So sorry if you have a string like that I guess the first thing we want to do Is just like differentize it Is how the space is or something like that That function already exists in Maxwell Okay so what does it use? Words Oh it's just words, I'm sorry did you just say that? No There you go You can try to write it yourself It'll teach you a little bit about the list The string itself is a list right? It's a listed car So you're going from listed car to a listed listed car But yeah you can use that And then if you do words Cat scares dog Because cats are evil There you go And since you know a product It's going to be SVO You know the second word should be a verb And you can go into As much depth as you do Or you don't want to And then we have some examples Of different kinds of connotations So these are regular So you have just limo Limon Air regular Strong Aerial weak Nominal Transitive So like transitive You can think of it as being kind of like Aerial Right? So what does that tell you? If you have a diatrain to the data constructor How many are you going to take? What is diatrain? Or is it only taking something too much? Sorry Well actually it's been a long time Been the hang of it Anyway we have it all Okay so you have that exercise And you have The exercise right And here Yeah And one more I'm going to stop But I'm telling you how many cabinets Are on word 8 I'm just asking how many cabinets Is each of these pipes have I showed you the outro This is arithmetic right So Just going to plug in Thanks for your time