hey guys last week i gave you an intro to functions basically what they are and how to create basic ones this week we're going to continue that going over some more interesting concepts that are involved with functions a curried function is a function that is applied to its arguments in a particular way consider the following function that takes two arguments here add add looking at its type signature is the same as a function that takes an int and returns another function that takes an int and then finally returns an it so what are the consequences of this so basically we can apply arguments to add one at a time here so we could say add 5 creates another function that takes an int and another int notice when assigning this function add 5 here we don't even need to specify its argument y so there's implicitly an argument why here when you return add applied to just one argument so this is a this is a function here but you notice there's no argument specified here that's okay the argument is implicitly there add5 returns a function pretty cool eh in haskell all of our functions are curried by default now this is not the common for most programming languages but haskell is an ultra cool ultra sophisticated programming language currying is particularly useful for working with something called higher order functions now a bit of a warning here we won't be talking about higher order functions for a while um so i'm just bringing this up as a bit of foreshadowing of what's to come it is possible to specify a unparade function basically just by using a tuple so instead of writing your arguments um one by one like you usually would you group your arguments into a tuple what does this mean this means that you can only call the function by specifying all the arguments inside of the tuple so now it's not possible you restricted it so that it's not possible to specify the function one argument at a time you have to specify them all at once so an example of this uh with the add function from before is we take those two instead instead of separating them by the error operator we take the two inputs and we group them into a tuple and the implementation is going to look like a tuple as well when we write the arguments polymorphism is a very useful feature of a programming language that allows you to create functions that are generalized over a variety of type so take for the length function for it for instance the length function takes a list and gives back the number of elements contained in that list in the form of an it it'd be very very annoying if we had to create different length functions for different types of lists so say we had a list of integers a or and a list of bool it'd be very very annoying if we had to create different length functions for each of these list type instead the default leg function we're able to write the type signature for it as length takes a list of a so note a is not a type here we can tell it's not type because it doesn't begin with a capital letter all types have to begin with a capital letter whenever you see something that doesn't begin with a capital letter in place of a type that means it's basically a placeholder so just like in algebra where we use like x and stuff as a placeholder for actual values this is a placeholder for type if you call it a type parameter a good intro example of a polymorphic function is the fifth function which takes a tuple and returns the first element of that tuple so you can see the generalized type that vs code is trying to give me the most general type is just a b goes to a okay so the nice thing about this is i shouldn't have to write a different fist function that for working on different types so i shouldn't have to write a different function that's going to return one okay when working on a tuple of one and two or a function that's going to turn true when working on a tuple of true and false okay i shouldn't have to define different like this int and this bool here because if you were to look like how would i define this end if i had a function fifth dent that worked like int goes to n how would i define this function well i define it as x y equals x same thing here right same as how would i define the function fistful bull bull goes to bull same way right so the idea here is i could define these functions that restrict what type i'm doing or i could just notice the fact well that all of these have the same implementation right and as of x and y equals x okay all of these functions are going to be written the same way regardless of what type it is here so if i leave the type signature using type parameters a and b instead of specifying the specific type now i can use this one fist function for all of those different types some other examples of polymorphic functions include these list functions like reverse and head and map so reverse for instance takes a list of a and it returns that same list of a but in reverse it reverses all of the elements so notice how this is a list of a goes to a list of a not a list of a goes to a list of b that would actually be the wrong type why is that so whatever the input type a so you're going to have an input it's going to be list of a and whatever that a is it could be anything but then the return type has to be that same type a okay so you're specifying whatever the type of the input is the output has to be that same type this is the same as for head you're saying head takes a list of a and it returns the first element of the list okay so whatever the input type is it's some list of a the output type is going to be that same a now map is a bit more of an interesting function so map it takes a function as its first argument okay so its first argument is actually a function and then what it does is it takes a list of a as its second argument and it goes through that list and it applies the function to each element in that list so the function takes an a as input so it's going to go through this list and it's going to take each a and it's going to turn each a into a b so then the output is going to be a list of b so make note when writing polymorphic functions whenever you specify a type parameter the output type might have to be that same parameter so you can't you can't just say well it takes a list of a it returns any sort of list b when in fact the output type needs depends on the input type a good example of this would actually be applying the map function to this okay so let's say we use map and we use map with fist of a list of tuple of 1 true to false three true and we get back a list of one two three like this okay so let's look at the type so the type of the map function is a list of a or sorry it's a function that takes an a to a b and a list of a and then returns a list of b so let's paste this up here just to keep track of it and then the type of the this function is a list of a and or a tuple of a and b goes to a here let's place this here so the first thing to note is that when i'm defining the type signature or map okay this has nothing to do with the type signature for this so i can actually replace this instead of writing a and b here i can just write basically anything else so let's say m and n as long as it's lowercase goes to m here okay now the interesting thing that's going on here is um when i when i apply the map functions when i do um this operation above of applying map to fist and it applies fist to each element inside of this list okay the function a goes to b here that's the same as this right here so the a goes to b okay is actually in this case m n goes to m so the trick here to notice is that a equals mn and b equals and actually sorry b well no no sorry b will equal m um just a note as none of this stuff is meant to be loaded into ghci in case some of you guys are trying to load engine ghci i'm just writing it to explain to you in fact um you might have noticed beforehand when writing fist and stuff these are functions that are already defined so if you're trying to find them again and load them into ghci that'll give an error okay so in this case the a goes to b is actually this fifth function the moment i give map this fist function it's it's doing this like substitution where a is actually m and the tuple of m n and b is actually m here so then this list of a here ends up being guess it what's a here the list of m n and this list of b ends up being you guess it okay this list of b here what's b a list of m so we have to play this game it's just like algebra the algebra alert you have to play this game where you're substituting in the types as necessary if you have a function g that outputs the same type as the input of a function f you can compose them into a new function z like so so the trick is to use this dot operator so the trick is f will have the same input type as the output type of g a good example of this is if we wanted to define a function lastlum that will take a list and will return the last element of that list so this is kind of the opposite of the function head i showed you before that takes a list and returns the first element of that list so we create this by combining that head function actually with the reverse function that i showed you before so let's say i have head composed of reverse okay so just just as a reminder reverse here it takes a list of a and returns an a okay and reverse takes a list of a and returns a list of a so reverse takes a list of a returns a list of a and then head takes that list of a that reverse returned and returns an a so these both chain together to create a function that takes a list of a and returns an a and just like before where i showed you with the curry functions you'll notice that this is a function but i'm not writing its argument so there's no x's here okay i don't need to write its argument rather i would say that its argument is implicitly there if i were to write its argument what i would do is i would write x's here and then i would put these two things in brackets and write x's afterwards so i put these two things in brackets just to be like these two things get put together to create one function that then gets applied to x's now that we learned the composition operator now is a good time to bring up another extremely useful operator that is basically this dollar sign operator so this dollar sign operator is very useful for dealing with parentheses so in functional programming in particular we get a lot of build up of parentheses so here i have a kind of complicated expression you're not going to know exactly what's going on in it right now but i've just written it down to illustrate how easy it is to build up this like backlog of parentheses and you can imagine when writing this expression when fixing all of the parentheses at the end here you might miss one or add an extra one and that screws up your program so to make this a bit easier we can use this dollar sign operator so we have this mashed up function here with all of these parentheses so what we could do is we could get rid of some of these parentheses so wherever we have a parenthesis that runs all the way to the end of the expression here we'll do is get rid of this one and instead put a dollar sign here so this dollar sign it assumes to be this a parenthesis and it ends all the way at the end of the expression okay so we can put a dollar sign here now we might be tempted to put a dollar sign here but we can't if we were to put a dollar sign here it would screw stuff up so like let's say i deleted these two this wouldn't be the same thing as what i had here where there's two parentheses over here this means a dollar sign parentheses open parenthesis and parentheses at the end here so we can't put a dollar we can't put a dollar sign there but this parentheses see this parentheses goes right to the end another dollar sign this parentheses goes right to the end here another dollar sign finally this parenthesis right to the end here another dollar sign and see how much nicer this is it gets rid of all of those piled up parentheses at the end it can't get rid of all parentheses so like the parentheses i needed for the plus sign and the plus two here i need to keep but it still manages to get rid of probably the most annoying parentheses which are the ones that pile up at the end there type classes are very important feature of haskell that extend your ability to do polymorphism they allow you to find functions that have different implementations so that means the actual definition of the function like the thing besides their type signature is going to be different depending on the type of their input so these functions that belong to a type class are called methods is another name for them so a good example of this is the prelude type class so this is a type class that already exists in the prelude and it contains the following method okay this is eq the double equals and the slash equals which means does not equal so this allows you to compare values so in order to actually use this type class you need to make a instance of the type class so you notice the type class definition it only has type signatures so there's only type signatures here and there's a type parameter to it a now when we make an instance of the type class what we're going to do is we're going to say the instance we give it the val the type for a in this in this type instance bool and we say this is how double equals is going to be defined for bool so we're saying x double equals y and we check if x which x is a boolean value so this is the same as saying if x is equal to true then if y is also equal to true then we return truths true otherwise we return false else if y is also equal to false so if both these things are false then we return um true otherwise we return false and does not equals we get defined more simply because we already defined equals as just being the not of the double equals the cool thing here is that we can make more instances for int and float and so on however those are a bit more tricky to find for equals here because end and float and all those things have infinite values but each type here okay is going to have a different definition now there are a variety of pre-built classes that come inside of the prelude so eek so for equals is one of them and it's defined for all of the basic types so all of the usual types that we use like bool and char string int integer float all these things eq is already defined for so you don't have to make definitions for it that means you can use this double equals operator and this does not equals operator with anything any of these types and there's some other types like show read which we don't really need to worry about for now and then there's even more complicated types that actually depend on the other type classes so when i'm saying eq and i use this operator here this bind operator ord what i'm saying is in order to have an instance for the orderable class for any of these types you already have to have an instance of the eq type so in order to have an instance of bull for the orderable type which allows you to basically say is this less than this or is this greater than this you already have to have an instance for eq which would kind of make sense because does it make sense to be able to say oh this thing is less than this other thing and this thing is greater than this other thing when you can't even say if these two things are equal to each other so there's a few more classes like this one that we'll see a lot is the num class so the num class is what um defines the operators like plus and minus and times the basic arithmetic operators and then there's some more complicated classes that depend on the num class like fractional class so if you use division at any point you'll see that you need it needs to be part of the fractional class and there's actually there's two types of division there's integer division which is that div thing and then there's the division which is the slash okay and that's the floating point division we'll talk a bit more about these later a polymorphic function is called overloaded if its type contains one or more class constraints which basically is a result of a function using a method from a type class so take the function sum for example so sum takes a list of a it sums all of the elements inside of a inside of that list and returns the result which will be another type a now we could have written some as being the list of int goes to ent or the list of float goes to float however the most general form of its type has to do with the fact that it uses the plus operator so the plus operator is part of the num class so what we do is we we write it polymorphically saying this could be any a except it has to be an a that is part of the numplus that has an instance of the num class so take this function add for example so we could write a function add that adds together its two arguments x and y and we could give it the type signature and goes in goes in and that's fine however now it's constrained to just working off of in so if we want it to work with float or some other num type we would have to then define another add function so what we're better off doing is giving the more general type it's most general type of num a and then we use this bind operator thing which is the equals arrow and then we just use the type parameter a so we're saying this function instead of just being an int goes to n goes to int it can be any a as long as that a that type a has an instance in the num class okay so in general when we write a function that uses a method of a type class we're going to have to specify in its type the type constraint like this another example along the similar lines is the add function is if we wrote a divide function that uses the fractional division okay so this operator this division operator is part of the fractional class so it's most general type so we could write for instance divide takes a float and another float and returns a float okay but that it that wouldn't be its most general type its most general type would be an a and another a turns n returns another a where that a is any a that has an instance of the fractional class now a good trick for investigating this stuff is to load up ghci and you can actually use this special uh it's like the type method okay you press a colon and great info and you ask for info you could actually info anything but a good use is info the operator so if it's if it's an operator like this that's meant to be used in infix notation so in between two things put it in brackets and it'll tell you that oh this operator is part of the fractional class and then we can ask it for info like all right let's ask what's what's the fractional class all about so just colon info so in general you just colon info almost anything you want to learn more more about and if you write colon info you'll see it defines the fractional class it tells you what are the methods inside the fractional class so there's actually a few more methods um this recipient from rational let's just ignore these for now and it also tells you what the instances of the functional class so the fractional class works on float and double so if i have this divide function i can say divide 5.0 and 2.5 right and i could force it to be a float or i could force it to be a double by explicitly writing the tight with this colon colon afterwards okay and this will be more important if you're actually doing a irrational division double and load you'll see double allows you to have more accuracy than float here but float will be faster okay so you might want to switch between the two so if we write divide with the fractional class here it's going to be more flexible and there's also another divide that we could have created let's divide two that uses a different division x div we use these bound ticks here because div isn't like an operator like this it's just a normal function so if we want to use it in in between notation like in fixed notation we have to use these kicks so remember that baptic that's at like the top left of your keyboard usually x div y and you'll notice the div function does integral division okay so integral division means that it's going to be an int type of some sort so if we have we could save this make sure to save before you reload and you do call and read to reload here you divide two two three what ends up happening well this just returns zero because it's literally gonna say how many times can three go into two as a whole number like this right so because it's an integral and there's usually two um if you ask for input info on the integral class there's a few different definitions let's ignore a word for now the most important ones are int and integer and int and integer are similar to float and double in that int is smaller it's it's it's only able to um track numbers so high and then int integer is able to basically be as large as you want it to be in my other tutorial this week i go over conditionals and i go over pattern matching power matching is very useful for a variety of data structures in particular lists lists are a very important data structure i'll go over what i mean by data structure in particular next week but for now just take it for granted lists are a very very important data structure in haskell that's why i brought them up right away and usually the way i've been showing you to write them is using this special syntax with square brackets and commas now the interesting thing about lists is that this syntax of square brackets and commas is just kind of a special illusion that you're allowed to use i we would call it syntactic sugar a lot of programmers would call it for this right here so the the way you can think of a list is a list is a bunch of elements so each of these things are individual elements of the list that are put together using this operator this colon operator which you can call the cons operator and you put it together using the cons operator until you get to the end of the list and then you specify this special value which is you call this the empty list and it's just two square brackets with nothing in it so every time you see a list written like this you can also interpret it as being this is how it's actually written under the hood okay so this is what's actually going on here now the interesting thing here is we could define functions that use patterns okay of x colon x's so in this instance x here would be let's say one and x's would be the rest of this list everything else in the square brackets here so let's say i wanted to ratify the function head which pulls the first element of the list out so all i would do is i would pattern match x colon x's and i'll just give back x conversely if i wanted to write the function tail that removes the first element of the list i would pound and match x colon x's and just give back x's okay so keep this in mind when i rate the pattern x colon x's x is the first thing x is is the list that's the rest of the list now you need to know x colon x's doesn't pattern match to empty list so generally whenever we write a function that pattern matches so you should never you should basically never ever write functions like this that just pattern match on x colon x's what you should do is whenever you're pattern matching on a list you should always pattern match on on least x colon x's and the empty list so these are the two scenarios okay so if we look back at our tail function from before the proper way to define tail okay so that it won't crash if you give it an empty list is to give it the empty list case and return the empty list here now with head this is a bit trickier because what do we want to do so with head we say okay in the in the case that there is a list okay with more at least one element so there's at least one element to this list here this x colon x's if a pattern matches here then let's say it's the element of uh let's say it's the list of just one value then x will be that one value and x is will be the empty list okay so as long as there's one value it'll return it if you call safehead on the empty list we need to return something but what do we return well with safe tail we could return the empty list again because safe tail returns a list of eight it takes a list of a and it returns a list of a but with safe head it takes a list of a and returns an a so we can't return this and because had is polymorphic because it's just some type a we can't just return some random value like zero or something so long story short there isn't a good way to handle this right now you kind of just have to let it crash so what what you would do for now is you just use the error function from before there is a better way to handle this in the long run that i'll show you later but it's going to have to be many many tutorials later lambda expressions are going to be very very useful in a bit although at the moment you might not see a use for them but just take my word for it so lambda expressions are a way of writing anonymous functions so these are functions without a name so you use them instead of putting a name so instead of writing say f of x here equals x plus x you just write slash x and then you use this arrow and then you write the function definition so we could define um a any function that we've written before where we explicitly put the parameters on the left hand side we could define them with lambda expressions if i put and put the parameters on the right hand side and we would do this in curried form like this where we're saying we have a function that takes an x and this returns another function that takes a y that then adds x and y together so like i said this allows you to define a function without actually having to give it a name and just kind of putting that function like right in its spot wherever it needs to be so i already gave you a little bit of an introduction just a bit earlier to the map function which is a very useful function that takes a function as its argument which is a very interesting thing that we'll talk about a lot more later and it takes this function as its argument and then a list and it applies the function to each element of the list returning another list so take for example if we add a function um add one that just adds one to its argument and we wanted to go through a list and we wanted to add one to each thing in that list we could map this function add one to a list x's okay so so if we created this function sum one and we gave it one two three it would return back the list two three four map is very useful so i'll show you one example right now of lambda expressions so lambda expressions are very useful with map because a lot of the times you don't want to define say this add one function right here you don't want to have it just hanging around there somewhere inside your file when the only place you need to use it is inside of map right here so you would just define a little lambda expression before we conclude this tutorial today i'm going to give you a bit of an intro to the concept we're going to be going over next tutorial session which is a super important concept known as recursion this is a very important concept inside all of computer science so recursion gives you the ability to define functions by using the definition of a function or using a function inside of its own definition so take map for instance the way we would define map so we would define map by first applying the so f is a function that takes as input and we would apply f to the first element of the list okay so we're pattern match on the list x x's and we apply l f to that first element and then what we're going to do is we need to return another list so we're going to rebuild the list so we're going to use this colon operator so this is an element and we're going to use this colon operator to then create more of a list so then we're going to call the function map inside of its own definition so we're going to use map inside of its own definition i'm going to give it f again and then instead of giving it the whole list back its argument we're just going to give it the tail of the list x's here and we're going to keep doing that and it's going to keep evaluating this part right here until x's becomes the empty list and then we just return the empty list here so to really understand what's going on here let's look at an example evaluation so let's say we have our map function here and we try to apply a function plus one to the list of one two three so remember the list of one two three can be seen this way this is the true form of the list where it's put together using these colons here so the pattern matches this list here there's two scenarios it's either going to power match to this or this so it's going to pattern match because there's colons still you're gonna pattern match to this okay so one is going to be x here and two three empty lists is going to be x's so what it's going to do is it's going to take one plus and add that to x so we're gonna have one plus one colon map one plus and then x is here remember is two three empty list so we're gonna have two three empty lists here and then what happens is now ignore the rest of this ignore the rest of this part here and let's just focus on evaluating this again okay so now we have map one plus and two three empty list here is pattern matching to either x axis or empty list so there's still a colon here so it's going to powder match to this and now this time x is going to be two and x's is going to be three colon empty list so then this time we end up with one plus two map one plus three empty list okay so this gets evaluated again and see this just keeps happening until we get to map one plus and empty list and then this time it pattern matches to this case here right and then what does this get turned into empty list and now you can kind of like go back and you see now now it'll evaluate all of these editions here and you have the list of 2 colon 3 colon 4 colon empty list which you know is the true form of this list two three four and with that we finally conclude our tutorial today i know this was a very big tutorial and because we're at the beginning of learning haskell you have to kind of learn a bunch to get out of the way to get to the more um believe it or not complicated concepts inside haskell so i know i know this is a lot however the tutorials will shorten up in length in the future they'll shorten up in the amount of content but it'll be even more interesting content to cover so there's still plenty of interesting stuff to learn in haskell i hope you're looking forward to it as much as i