 My name is Aditya Godbole. I work at Virtus Micro Systems as the CTO and Okay, so before we start a set of disclaimers I am a Haskell fan obviously and but my interest is purely academic I mean, I don't expect to use Haskell in production at least in my company anytime soon But at the same time there's a lot to learn from Haskell even if you don't end up using Haskell in your production work I am in no ways a Haskell expert I am in no ways a Haskell expert so if you see something like Monads or monoids in the category of endofunctas or something like that. I have no idea what you're talking about Okay This is an experience report based on Interesting course we took internally in our organization. So There's a context associated with this talk and Needless to say this talk will be quite opinionated and Things that are true in this context may not necessarily apply to the context that you are in so please Make your own opinions about anything that I say Having said that it's important to state the context So we are basically a services company and we do outsource product development and product management and most of our Developers are hired locally from colleges in and around Pune We use Ruby JavaScript Python Java go among the popular or the more used Languages So the the question really is why Haskell and to begin with Why functional programming at all? I mean, I know this sounds a bit weird speaking at a functional conference, but There has to be a reason to do something to invest your time and effort in right So so far like the mainstream paradigm has been object oriented and we have got some pretty cool purely functional object oriented languages like Ruby and So why suddenly look at functional programming to begin with? so one of the things that I Do as part of my job is code reviews and Often The code is good according to functional According to object oriented principles and all that but I've often find that there's something missing something that There's a difference between code that works and code that's beautiful. Okay, and that sort of inches me now and then and through my experience, I've realized that at the end of the day, it is beautiful code that will scale and That will be more maintainable. So our inherent sense of beauty comes from Something functional. Okay, so why not? Oh, I mean this is this big Question mark that and question that have been asked to me quite a few times. What's wrong with? Oh, so before that we really need to See what we mean by over object oriented and what we mean by functional because there's a wide range Like Scala is functional groovy is functional Haskell is functional. So what exactly do we mean by functional? and What exactly do we mean by? So Firstly in my experience the traditional object oriented model really works at the macro scale and when I say macro scale, I mean One interface being worked on by multiple developers. That's the large scale. So what exactly do we mean by? So what I mean is You have these opaque objects and these opaque objects communicate with each other through Pre-defined controlled windows. So it's like there's a black box and there's some guy sitting at or multiple people sitting at windows and there's a Windows which allow you to access things inside that opaque object and you go to that person tell him Hey, I want this or please do something. He does something churn some machinery internally and comes back and gives you some answer Okay That's the ideal object oriented world where Everything is controlled through these windows and a set of or a contract of these windows is basically what you call an interface The important thing over here is the data exchange, which I've shown by green circles Ideally should be pure data Simple data that you can inspect not opaque but completely transparent in such a system Things work really well at the macro scale. I mean we have all talked about service oriented architecture That's nothing but a specialized case of Object oriented architecture like this where each of these squares are just single turns in a way the problem that I have encountered is We tend to do this right, so we tend to Make everything an object and that starts creating problems So even the messages that we pass among our objects end up being objects themselves And then you get into all the problems of mocking and blah blah blah, so to me Good OO is characterized characterized by three things opaque objects controlled interaction and Well-defined interfaces. Okay, so those are the desirable desirable characteristics of Object-oriented code, but when you start looking inside these objects, right? We come to the micro level and that is basically where one developer is working with multiple interfaces That's where things sort of start to get ugly when you try to impose the same object oriented principles So what is it that you want from the code of water desirable characteristics of the code at this level? So firstly you want to be working with data. No strings attached, right? You don't want a method on it getters setters Nothing. Okay. Same simple data if it's immutable. It's a bonus, but It's really important that the data be completely transparent There should be no Overhead of methods that goes along with the data the reason is A when you try and get into all the mocking stuff So the real problem with TDD nowadays is not Not TDD itself, but that we have to mock functionality instead of mocking data, right? And that becomes really painful, but if you have simple data, I mean think Python dips or C-structs or Tuples if you're talking as kill then it's it's very simple to simulate these and it's very simple to Reason and test about small pieces of code, which is what a developer is focused on at any given point of time The second and I think the defining characteristic of sort of functional code is atomic operations now When I mean atomic this is nothing to do with thread safety and all that atomic. Okay, so consider a function where You take any newbie programmer and ask him to write a function Which takes in two integers and returns the sum of those integers There's a very less chance that that programmer is going to go wrong in writing that function. It's very simple return a plus B So why I mean if you look what actually happens on the machine if you consider a standard for Norman architectures Even if you consider a risk machine, this is going to boil down to something like a couple of instructions at least Right, but the reason the programmer does not make a mistake in writing a simple addition function Is because the compiler has abstracted away the complexity of all those sequence of steps that needs to be done From the programmer right the compiler gives you a single operation Denoted by one operator plus That's it. You don't have to worry about what sequence of operation happens Okay, so that I think is a defining characteristic of any functional code So the difference really is not Object-oriented versus Functional, I think it's declarative versus imperative in the declarative style You basically tell what your intent is you say what needs to be done Whereas in the imperative style you give a sequence of steps and you say how that needs to be done And the intent is implicit Okay, sometimes if you see large chunks of code you have to like really scratch your head to figure out what the intent behind this code was You rarely get that problem with good functional code Now the interesting thing is we can we can sort of do a right code like this even in our mainstream languages, right? We can write code. So if you really want to move to functional style try this trick Take any piece of code and convert it such that it doesn't have any reassignments Okay, zero reassignment to any variables What you'll be forced to write is a functional style of code Okay, I've done this exercise taken any standard piece of code from one of our repositories and just refactored it so that I Was not allowed to do any reassignment You can assign to a variable once you can't assign any value to that variable again, or you can't call a mutating method on that variable again okay, so If you so why can't we do that in a normal programming practice, right? We can always make all Java variables final We can always write code in even in Ruby or any other language where we don't Modify any variables. So One reason is a people are not aware that of this style of programming, but b. I think it's really a problem with discipline Okay, that's what I found. I mean even if you go and tell programmers Okay, if you use this style of programming look how nice the code becomes how readable and maintainable it becomes if you if they can If it is possible for them to not do it. There's a high chance that they will not do it. Okay, so this talk is really about how to use Haskell and Get yourself or inculcate that discipline in you by practicing in Haskell So How do you sort of inculcate this discipline one very simple? Yeah, so Yeah, so I I mean it will obviously differ from person to person But I have had cases where Somebody came to me with code that they needed help with and I saw the existing code and it was like yeah So I just Refactored it right there in front of them from like 50 lines. It came down to I would say 10 lines or so Just by using a standard map reduce and all those things and at the end of it They were like wow, I mean this is so much more maintainable. So they really saw the value in that but next day again They wrote the same kind of code, right? So it also needs I mean a you need to know what to do But be you it's really As you say it has to come from the tips of your fingers to a certain extent Fish to the hungry person or should we tell how to fish? I'm just leaving it Yeah, I think you do need to discipline at least by my experience I mean they need to be convinced otherwise there I mean to learn anything you need to be convinced about it not not just Functional programming this goes for anything But for programming which is more practice as well. You do need discipline So what so I thought about what I could do to sort of get that discipline and One of this answer was to put them in a constrained environment Okay so when when I was a kid like we used to take our inter-society gully cricket matches really seriously and My brother like he had a problem with short pitch balls any time the ball used to rise above his chest I used to close his eyes and do this and He said okay, we are losing because of that we can't we this cannot carry on so in our house We had a similar corridor except it was enclosed on both sides And I started throwing the ball at him from a very short distance really fast Short bit stuff and the rule we made was you can either leave the ball cleanly or if you hit it It has to hit the ground first. It cannot hit any of the walls right 10 15 days of this practice and he actually got a lot better Because you didn't have any choice if the ball hit his bat and hit any of the walls He I started batting in here to get me out and he had to ball till I got out, right? So Of course it helps to be an elder brother So one option which had really worked for me was SICP. I mean that's that's like the classic You get a very minimal language According to me like the best or the most elegant language just in terms of language design that I have seen I Really recommend if you have not read that book Please do read it. It's a classic. It changed the way. I thought about programming So I actually went and experimented with this We took a self-study session and in our company itself. We did a couple of chapters from SICP but it didn't really solve the problem and In some cases things actually got worse So I started thinking what what it must be that that's missing, right till I stumbled upon this quote from this gentle this gentleman which is Bad programmers worry about the code good programmers worry about data structure in the relationship and that's when it hit me That was the answer, right the reason why SICP had worked for me was I had Like spent seven eight years working in languages like C and C++ Where I had no option but to model data in structs and it was statically type language So I realized that I needed to put these people in a statically typed environment but also very constrained in the environment at the same time and So this is also reflected in another age-old sentence from another very good book Fold knowledge into data so that program logic can be stupid and robust so So I was looking around for such solutions. I had no idea that something called Haskell even existed But my problem was solved when I met Mr. Modi Not that Modi this Modi. He's a lecturer at the University of Pune and he uses a Variant of Haskell for their internal computer science course now gopher is is actually a one of the predecessors of Haskell It was written something in 1990 or something and it's a very small language today. It's a subset of Haskell But it turned out to be exactly what I wanted Hey, it's written in C It has a very small code base and I can actually understand what that code does So there were times when I had to go and modify it the actual implementation itself like change how some operators behave and all that And it was very easy for me to do it because I mean I knew I've done a lot of C Secondly it comes with two preludes. So think of a prelude like a standard library Although you can also do things like define precedence of operators and stuff like that in the prelude itself So pu simple is a prelude that has no type classes if you don't know what the type classes doesn't matter But it is some it doesn't have type classes. Whereas the standard pu std does have type classes So pu simple will put you in a really constrained type safe environment and there's really no escaping it Also like all cool things nowadays it added a web interface so you can access it in the browser. So one less reason to not use it So what did we actually do? Now remember that this is about learning from Haskell not learning Haskell itself, right? So We concentrated on things that we can take from Haskell and apply it to our regular or the other languages like Python Ruby JavaScript Etc. So in that sense, it's about low the low-hanging fruit of Haskell and I thought it would be easy, but it definitely was not So let's so I'll go through some of the steps that we went through I'm not going to go through all the exercises and stuff that we did If you have any questions about the code, please stop me and ask Although if it something that will take time to explain we'll have to take it offline after the talk So we started with very simple functions things like so here's a function which It takes a input as a number limit and it returns the smallest integer Whose square is greater than the input. So for example, if I pass in 10 It is going to return me. Sorry if I pass in 100 it is going to return me 11 because 11 square is the smallest square greater than 100. So if I pass in 200 is going to return me 15. Okay So this is how you would write it in Haskell or go for So you can use where to introduce a inner function So if you've done JavaScript or Python, you would be familiar with the inner functions These things here, they are called guards. So basically this allows you to choose what Implementation of the function you want based on the condition that you give over here So what this says is if y square is greater than limit then this evaluates to y and otherwise is actually an alias for true So otherwise it is it or y plus one Simple now is this a iterative process or a recursive process? How many say recursive? How many say iterative? So this is actually a iterative process. Although it uses function recursion Okay, because Sorry, yeah, so this is a tail call So consider this call of the second call of it or y plus one, right? In the call stack, you don't really what you're doing is you're returning the value returned by this iter Directly to the calling function So you don't need to maintain any state of the calling function after you have called it or y plus one, right? So if you consider a stack-based implementation Instead of adding to the stack you can just replace the current stack frame with this new call Right and the process will finish It's not I mean, there's nothing in the calling function that is waiting for the result of this Called function. Okay, so this is a iterative process And that's how you do iteration in Haskell. Basically you use this thing called tail call Recursion and the Haskell compiler is intelligent enough to figure out that oh This is a tail call. I don't need to maintain the current stack frame and replace it Yeah So The I know a few languages which Say that I mean which have tail call Optimization of tail call recursion as part of the language spec itself. So one is scheme second is Haskell you have Lua and maybe I've missed something else. Maybe you're lying Closure doesn't have you have to say recur explicitly I mean the JVM doesn't support tail call No, no, I think the reason closure does not have tail call recursion is because it's not implemented in the JVM Otherwise, they would have any day gone for it. So I was actually going to cover this in one of the later slides right so I Was going to cover this in one of the later slides But there are certain aspects of working with this that you have to explicitly mention when you are covering this You have to explicitly say that this is native only to Haskell and your language does not support it. So Then we go into how do you write something similar in your language? Okay, so we use this to Teach basic iteration versus recursion and the idea that basically iteration is nothing but carrying the state Over multiple function calls if that's one way to look at it and which is why you can use it in this way in Haskell So just some pointless refactoring Just to show that you can do this basically Okay the next thing that we took was The calculation of square root by successive approximation another thing directly stolen from SICP So this is Newton's Formula that to calculate the square root of any number you successively keep keep on calculating better Values so a new better value is the old value plus the number that you want to take the square root off divided by old divided by two you can draw the number line and you will see that it converges So this is again the same implementation You see The moment you take away Assignment equal to as an assignment you are forced to refactor it into smaller functions. Okay, this is you just can't do it any other way, so this is Again similar iteration again refactored just Because we can Yes now one thing that you get by doing this is You can introduce the concept of closures Okay, so for someone coming from Java or any other language which doesn't use closures exhaustively so this EPS for example Earlier it was passed to the function, but when I took it inside I can use the EPS From the lexical scope of the outer function. Okay, so this EPS can be used in the inner function itself So this is actually more than closure is lexical scoping But if you return good enough as a function itself, then that will become a closure So next we move on to something really interesting. So these are the two functions that we wrote right now if you see the iter Inner function over here you see a definite pattern over there Except for these things everything else the structure and all that is the same Right, so can we convert this iter to another function a generic function to which you can pass in these things that are different So you definitely can and this is how it will look Right, so what you have done is here you had iter had only one argument Here it has three the first is what you call the predicate the test The second is the function that you want to actually apply and the third argument was what was there? initially Right, so you're passing what was different as? an argument okay, and You get higher-order functions Okay, so one trick that I've learned over teaching in the university and other places is Especially for concepts which have big popular names like pointers or higher-order functions or Monance something like that. It's better to teach the concept first and then teach the name Right because people come with a lot of preconceived notions of these big names So remember in the when I was teaching a simple C programming at the university. I actually taught Most of the concepts of pointers by calling them address variables right including arithmetic and all that and people and all the students got it really well and All this was in one two-hour session at the end of the session I said oh by the way the rest of the world calls address variables pointers and they're like oh wow We know pointers That's great, and until then pointers is something that went in advanced C typically in the syllabus so I'm rewriting square root using the till function so Haskell comes with its own function called until So which is why I wrote till which basically does the same thing you can check the prelude And it's very similar Now there are two interesting things over here. The first is anonymous functions Right, so the first argument to till is actually a function which returns a bull It takes one argument and it returns a bull So this is any anonymous. This is how you write an anonymous function. So this is the parameter X and This is the body x square greater than limit Okay Similarly the second is also expressed as an anonymous function The good part is that it reads very naturally It's an atomic operation. No looping no modification of variables. No I greater than Nothing till good enough epsilon and X improve X starting with X by 2.0 It's signaling intent not how to do it There's a very interesting thing happening over here How many of you were in Venkat's Haskell talk in the morning? Okay, so he covered something called as partial application, right? so Though identically, it's sort of a bit different but Haskell has something called as currying which means that if you define a function with three parameters and If you pass it just one parameter It's not going to complain instead it is going to return you a function which is going to take the remaining two parameters Okay, that is called currying. So in fact Haskell the way to think about it theoretically in Haskell is Till is a function which takes the first parameter and returns a function which takes The next parameter which returns a function which takes the last parameter So you can pass any number of parameters obviously less than the arity But if you pass two parameters Haskell will return you a function which takes the third parameter and will compute the output Okay, so this is what we are doing over here If you remember good enough took three parameters epsilon x and y So what we are doing is we are passing just two parameters to it and Haskell is going to return me a function Which takes the third parameter, which is basically what P is Right P is expected to take one parameter and evaluate to a bool right now the beauty of all this is if you make any mistake in this That the type-checking system of Haskell is going to scream at you So remember so till now we have not talked of types at all But behind the scenes there is a very elaborate type inference and type-checking system Which is going to check your types every single step of the way How many of you I mean I guess most of you when in school we did physics, right? So on one hand We did equations and on the other hand we did something called as For what it's called basically you do the unit checking right Dimensional analysis, so it's very similar to that if this is your code Which is that actual equation the dimensions also have to add up and that's what the Haskell compiler is doing behind the scenes It is so think of pipes as the dimensional Equivalent So then we move to lists So Venkat covered some of the standard functions which you get on lists in Haskell So we actually implemented all of those and they're really simple to implement Again some interesting things over here This colon colon operator actually in Haskell it is colon. I've converted it to be colon colon in gopher So the colon colon operator is used to create a list So the empty list is predefined You create a one element list using this this three colon colon empty list So this this will give you a list containing one element, which is three You apply the colon colon operator to that and you get two three and you apply one colon colon to that whole thing You get one two three so list one and list two are identical Okay This is called a constructor operator. You can have constructor functions as well, which we'll cover a bit later But this is a constructor operator. It takes two things and returns you a new type Okay, or it constructs something for you On the right hand side this operator works as a constructing operator on the left hand side of a equal to this works as a deconstructing operator So this is something very new to Haskell Or very different in Haskell. I think MLO it's picked up from ML, but compared to the other languages. It's something very different So what I'm saying is the input if it matches something like x colon colon underscore stands for don't care But something right so which means that this function matches x colon colon anything else The return value is x which is exactly what a head does to a list okay tail is The first parameter which I don't care about colon colon the rest of them the X is It's going to be deconstructed over here and I return the X is Okay Last has two definitions and depending on what pattern matches your input that particular definition will be chosen at runtime So what this says is if I get x colon colon empty list Which means a list with just one element then I want to return that element Otherwise, I want to return last of excess is again iterative process or recursive function. Yeah This compiles why I guess not So that's another thing has killed you right if it if the type system does not so these These patterns so what he's asking is they were not are they exhaustive do they cover all possible scenarios? So if they don't cover all possible scenarios on the left-hand side the Haskell type system will actually give an error Saying that this is not an exhaustive pattern Okay, so that is Haskell in go for that flag is on my default as an error Yeah, probably I Need to check but I think this this code compiles so it wasn't it was Yes, no unless you are going for Scala, I think What is So two things about that one is So From from the code at least in our organization I see map reduce and all that being used pretty frequently Relatively what you're really missing is this Right the kind of abstractions you can create out of this. This is what was really missing so Map and reduce as I said, it's it's the bare minimum you need to go one level above This that's what I was really targeting So that's the first part second as I said, wherever there is deviation We actually covered how to implement this in your regular language What is the best pattern to implement this functionality in your regular language? so Like for every session like this was followed with language specific sessions for how do you do this in your language and That is very necessary Same for in it reverse Just for reinforcing. This is a iterative version of in it. So this in it is recursive you're using the return value of the next call and You're doing a con operator on that. So you're waiting for what the call function returns So this is actually a recursive process as well. This is the iterative equivalent of it and Then we introduced List comprehension, so I don't think it's fitting but yeah is everyone aware of list comprehensions Anyone who doesn't know list comprehensions Okay, a few people talk to me outside Next we introduced data and like structured data so This is to force people back into the old C struct kind of days Even with python dicks or ruby hashes by the ruby hashes like a completely different monster compared to a python dick but Just think C structs The difference between a python dick and a C struct is you have to You have to decide the structure at compile time Whereas a python dick will just accept anything you put in it. There's no enforcement of structure and That is something that I found was really lacking or missing in program designs So this So this data basically is defining a new Struct type which says that it's just a struct of two floats Okay, and we just took a point Considered as a vector and it just entered Distance formula and vector sum vector magnitude etc as you see again This is deconstruction being applied on the left side. The thing that we introduce here is Creating new values from existing data instead of mutating the current data objects in Askel basically so What if I wanted to change the x-coordinate of this particular point, how do you do that in Askel? There's no mutation Well, you can't do it in Askel the solution is to create a new data value with the changed value as you want Okay, and at this point you really have to go into things like immutable data and Efficiency of cloning and explained that there's no real cloning and all that and that this does not apply to their languages Okay, otherwise you'll get people cloning objects all over the place So initially I did not insist on writing the type signatures Later on as you you'll see I did insist on writing type signatures But it is very important at every single step of the way to open your repel and ask them What is the type of this like even if you do a simple a plus b? What is the type of a what is the type of b? What is the type of a plus b? What is the type of plus? Right, it is very important to ask them and come continue to quiz them on the types of all of these Okay, oh by the end when I'm talking I'm talking from the point of view of teaching Someone but if you're interested in self-learning basically applied to yourself Recursively Yeah So trust me people are not going to get this right at the first attempt and they're going to run into the type checker Every single step of the way. So even if they don't want to they are going to be forced to confront the type checker So here I'm just showing code that works Getting to this point takes along a large amount of time especially for someone new to ask Right, so this is so here you introduce the notion that instead of mutating Object you just create a new object from whatever parts you need and it works because it's really efficient, but It's important to also cover In their specific language when to clone when not to clone And what is efficient in their language and what is not right, but at least They see the possibility of writing real world programs by not having any mutation and We typically finish with Like a largest sample a largest example. So this particular example is about So this is a simulation example, you know as stateful as it can get so what this does is let's say you have a circle of n people The first person Let's call them index them zero to nine nine nine or zero to n minus one if it thousand it's nine ninety nine The zero person has a sword. He kills the person next to him passes on the sword to the next alive person The next alive person also kills the person next to him and passes the sword on and this continues till there's only one person left So what is the index of the person who survives at the end right a very stateful operation? it's a simulation exercise and I usually use this for as an introductory example in other languages But I and I ended it the course with my has to course with this again some interesting things over here so Zoom I don't know whether it will work. Let me try this Oh, it works. Wow So the interesting thing over here is So Venkat had mentioned about the composition Composing functions together and it doesn't really work well because it goes right to left So in go for I've actually modified this and replaced it with the comma Operator which actually does left to right so think of it like a unique spike. So this entire thing is a function To which if you pass an argument it will first go Through at the result will go to kill the result will go to replace So it's it's more it's easier to reason about function composition like Unix pipes rather than the other way round and that was another advantage of go for that I could quickly add in a function like that which behave the other way instead Can I zoom out? so What I want to show next is some examples of so what I did was I took some old code and After this entire course, I gave it to one of the guys to just refactor. This is your code Now you have gone through this course. Now, please refactor it for me Using whatever you have learned You see there is lots of stuff that is common repeated patterns. You can see But it's not that straightforward because here you have something called as registered drop-down which takes drop-down Okay, we have to cut down. I just want to show the last one This is what it ended up with after refactoring the interesting part for me is this part Okay All right, so If you are going to try it, it's just last few words It takes a lot of effort. It takes a lot of investment You will often face resistance if you want to do it in your Organization they'll always be the question of what if we invest so much to train our people and they leave At my standard response to that is what if you don't invest in training your people and the state? Thank you for your time