Episode: 2838 Title: HPR2838: Why Haskell? Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr2838/hpr2838.mp3 Transcribed: 2025-10-19 17:46:00 --- This is HBR episode 2008-138 entitled Y-Ha-Kell, and in part of the series, Ha-Kell. It is hosted by Tuku Toro-to and in about 32 minutes long, and Karima Cleanflag. The summary is, Tuku Toro tries to answer even question on why would someone want to use Ha-Kell. This episode of HBR is brought to you by AnanasToast.com. Get 15% discount on all shared hosting with the offer code HBR15. That's HBR15. Better web hosting that's honest and fair at AnanasToast.com. Hey, hello. You are listening to Ha-Kell's Perfect Radio, and this is Tuku Toro. When I made an episode about functional and applicative in Ha-Kell, yeah, episode 2778, I caught comment from Ibiza, which is following. I have been writing software for over 30 years, but I find the syntax of Ha-Kell anything but any. Anything but intuitive. Obviously, I am missing the point, as nobody will design a language through the intention of it being difficult to use. Perhaps you could produce another episode address in the question, why Ha-Kell? That's a really good question. It's good idea to be a critical, never take anything at the face value. And this episode is my personal view about the matter. I might be overstating something, I might be missing something, but this is the reason why I like learning Ha-Kell. So, Ha-Kell is originally an academic research language, it was not. The youthfulness was not the top priority, the priority, back then it was for the research purposes, but it has gotten more and more usage in the mainstream. And the main point for me in the Ha-Kell is that it makes me think differently about the programs I write. There are some features that I will go through a bit later that pretty much forces the programs to be completely different to what I normally write. And I like being out of my comfort zone when I'm learning new things, and I think that it's not up. If I'm learning a new language, it doesn't, it doesn't usually make that much sense to learn a new language, if it's just almost identical to the previous languages you have known. So, Ha-Kell is different, Ha-Kell first me to think differently about programs, so that's why, that's the main thing I like about this. But if you want to evaluate a program language, you should concentrate on the little parallel tricks or little details. You should test three questions, you should think of what are the primitive elements, what are the means of composition, how do you compose those primitive elements, and what are the means of abstractions, how do you draw boxes around these compositions and make them usable. This question is from the Harrod Abelson who was the co-author of the structure and in the presence of the computer programs, which is really terrific, book and really good video series about the book on the YouTube. So, you should concentrate on the parallel tricks, you should concentrate on how some short code can do some nifty things. And since the existence is that important, it is still important, but only to a certain level. So, things like, are you using parenthesis or not parenthesis? I used your code in list, now I'm coding with the Ha-Kell list, but at least look like the list had tons of parenthesis, and Ha-Kell doesn't have pretty much anything. But, it's not big difference, semi-columns, or no semi-columns, meaning full white space, or not meaningful white space snake case, that was common case in naming. Like, I used to do quite a bit of Python, they used the snake case, so you have a multi-word name, the words are separated with the underscore, as in the Ha-Kell, they're using common case, with a lowercase, but the words start with a lowercase. And when I switched from the Python to the Ha-Kell, that's something I totally didn't like at all, but it didn't take, it didn't take that long to get used to it, I don't think of that anymore. It is true that Ha-Kell has some things that make it, on a first glance, quite a bit difficult to read, like, we have this, we use a lot of symbols, like, code is literally the dollar diamonds, dollar diamonds, abstract diamonds, pipe diamonds, question mark, dot, crater crater, equal, which is fine simple, crater, equal, crater, crater, exclamation mark, exclamation mark, and what not, like, there's lots and lots of those, and if you don't know what those are, it's pretty much impossible to read, I wouldn't think. And the information density of the Ha-Kell code is very high, there's a quarter, there's not that much boilerplate code to write there, abstracted away, of course there's always some, but some, some things are abstracted away and replaced with smaller constructs. So one theory is that when you have less code to write, then you have less blocks if the, if the complexity of the program is the same, but I don't know if that's true. So, our primitive elements, so Ha-Kell has usual primitive data types, like int, float, and so on, then it has this allocation, allocation type, data types, pool and maybe a, e to ap, that can be used to express cases where you have a, you can have a numberation of different cases, and those enumerations can be parameterized. If they are, they are records, these are just collection of fields with types, for example, person could have a person name and person age. This, this is one part that I don't quite like about Ha-Kell is that the record field, when you have a defined record with fields, those field names are used as a functions, so when you want to check them, if you are, when you want to check a, for example, age of the person, it is usually person age, and then the data, and then you get that one value out of the. So, because those are functions, they are not, they are not encapsulated in a same way as in the object oriented programming. You cannot have two identical, two functions with the identical names in the same namespace, so you, it have to keep the records in a separate namespaces, so the, the fields to class, oh, you have to prefix them, I usually prefix them with the record name, so person would have a person age, person name, and person occupation, fields of name, age and occupation. That's, I don't quite like, and then there's a functions, and there's a lot of functions. Functions are pure, meaning that they are always data in, data out, they don't mess with anything else, and you cannot change the parameters that are given to you, if somebody gives you some record, as a parameter, you cannot, inside of the function, change values of the record, yeah, immutable. So, then this element, it, this eliminates quite many bugs in my opinion, at least in, since I have often run into the case where I'm doing something, I'm using some function method, somebody else wrote, and that, that forms a long chain of method calls, and then somebody, somebody changes the value of the, that's in object for some reason, and then it, everything seems to work, and then later, later on when testing that record, that this time we got it all. So, and of course you can have side effects, but these are different, different things like, if you are, if you are, writing to a disk, for example, these functions are, they have different kinds of types, types signature, so you don't actually, you then actually even call, accidentally, call a function that touches a database, without you knowing, you can see that clearly, from the, from the function signature, and you, that signature signature bubbles up, like, if, if there's a one function that touches a database, then the function that is using that function, also have to state that here, I'm touching the database and function that uses, that one has to state that, by the way, and touching a database, you cannot, you cannot hide the fact that something is having an effect on the outside world, it's, it's visible all the way to the top. Like I said, data is immutable, so, let's move parts, let's box, I like that, and the other thing is that there is no null, has, has, when you, you cannot have a null value, you, nobody is going, ever going to say that I'm going to pass you a person data, and then accidentally hands you a null, you don't, that just doesn't happen. There is a, there's of course a way to express in situations where you are, where you are handed a data that might or might not be present there, but again, it's explicitly, explicitly said, stated that this might or might not have a, the data you are expecting or going to use, and but it's still not now, it's a value, and also the compiler will check the times, and tell you that, by the way, this is a type that can have a value, or cannot have or might, this is a value that might or might not have what you're looking for, so you have to account for that. And data, undefined though, undefined is a value that does not exist, so, if that's usually not really used in the house school, at least I haven't figured out any use for that, there are cases where you might have a function that doesn't always return a some sensible value, then it might return undefined, and then that would cause a runtime exception and the whole thing would halt. For example, head is a good example, if you have a, if you have a head is for it returns to the first element of the list, and it has a type of list of A to A, so if you give it a list of something, it will return something back, like if you give a list of int, it will return int for you, but if you give it a empty list of, empty list, then of course it cannot return the first element of the list, but it doesn't, it says that it returns something, so there's no, there's no case for that, so it will crash. So those are, those are called, I think, part of the term, the functions that always returns value, when given a lot, given parameters are called total, and functions that have cases, or like x cases or corner cases, so they cannot return value of a puzzle. Okay, means of composition, so I will try to tell you that it can contain other lines, so you can, you can have a, for example, you can have a, maybe that can, that is an example I often call, maybe it's a, this data data that signifies that they can be value, or they can be lack of value, so that can be a maybe int, can have values of just int or mapping, so this is, pipe that has been parameterized with a, pipe int, they can be specific, or they can be general, like you can, you can specify that, or, for example, in the case of, maybe you have to, you can put anything there, of case of list, you can put anything in there, or you can have special data type that, that have, I don't really know, you have a, can, can you think of good example, right now, but you, you could have, my maybe int, that is always parameterized with a int value, so that can only be int or mapping at all, and they can be recursive, so you can, on a type level, you can, for example, define how binary three is formed, so you, you three, three consists of branches and leaves, and that's gotta, nice. Records work in the same way, you can record fields, because they, they can be, any time you can put more records there, or you can put algebraic data types there, and of course in the algebraic data types, you can put records in, functions are values, these huge thing in functional programming is pretty common in, in object-oriented programming nowadays, meaning that you can, nice functions as parameters, two other functions, you can return functions from functions, and you can store functions as a, as in a, and some data structure, you can have a list of, you can have a list of functions, but in hospital they have to, if you have a list of something, they have to have the same, same, same data type, same type, so if you have a list of functions, those functions have to work in the, they have to have the same signature, and you can compose functions with a dot operator, so you, if you have a two functions, one is from A to B, so you are, if type A, and if returns type B, and then you have a function that takes B, returns C, you can compose those with a dot operator, making a new, new function that is from A to C, so you just treat them as a pipes, the ends of the pipes fit together, so you just snap them together and form a new, new function, and this is cute, quite often, to take those simpler functions, combining them together, making a larger, larger functions, often on the fly, then you need to call something, you don't, you don't even have to give these new functions a name, unless you absolutely want them, but usually you don't, and because functions are pure, like it's data in data out, you, the, you know that you can, safely combine them, normally in the middle is suddenly going to format your hard drive, or well data from the database, or right to the hard drive ending like that, means of abstractions, so functions can apply other functions, like data called other functions, and you can use, best in functions, has to feel slow, you know, some general algorithm, if you have a, for example, if you have an algorithm that sets path through a maze, you can abstract out the decision to, which direction to go next, and just say that this general ruin expects a function that looks like this, and it is used to choose let go next, and then you can, then you can use the general algorithm, and when you are setting things up, you can give it a function, and then you can do path first, or depth first, or beam search, or ASTAR, with the same general algorithm, you are just replacing the decision making, slot there, so, and functions can be, they can be parametric, polymorphism, the superparametric, polymorphism, so, I am sorry, the data type support, the parametric polymorphism, so list of A, maybe A, I talk about that, but you kind of have cases where you don't want to specify very clearly that this is a specific type, but you also don't want to allow a prox type like everything, and here the type classes and type constraints come to play, so you can have a function that expects any type that supports equality, so anything that can be compared with each other, or you can have a function that expect ordering, so you can see which thing is bigger, or you can, and you can have multiple constraints of course, so this allows you to write a critical neural code, if you know that you are doing some calculation, you can say that you are, I mean mathematical calculation, you can say that you are expecting a values that support, for example, NAMM, numeric operations, plus, minus, multipilization, and so on, and perform your calculations based on that, and that then your function works with anything that has instance of NAMM, meaning that when somebody comes with some new numeric type that has instance of NAMM, your function will automatically work with those correctly, and there are tons and tons of these type classes in the already in the existence, and some of them are pretty, pretty abstract like this, for example, this is a semi-group as a type class meaning that something that you can, if you have two elements, you can combine them together, and there is a monoid which uses a semi-group with identity, so you can, you have, again you have two elements that you can combine together, producing the same kind of element, and you have a unit element that when combined it's something that doesn't change the end result, and for example, list is a example of this, when you combine two lists, you just combine them, you take one list and then act another list at the end of it, numbers, indexes are one example of this, you, there's actually two examples for this, with now indexes, but one is that when you combine them, you place them together, and then the unit is zero, because zero plus anything is still the same value, or you multiply them, and then the unit is a one because anything multiplied with one is that original value, and it might sound that's pretty abstract, it is abstract, and not useful, but that's not the proof, it's really useful, when you, when you figure out what kind of things you can do with that, you, it starts showing up in the code all the time, so there's a lot of these useful abstractions there already in present that you just have to learn and start using, for example, for loops, there are no for loops, as, as in the same census, in the, for example, in the C-shop, if you want to, for example, if you want to take a list of elements and just find out all the, if you have a list of numbers and you want to find all the numbers that, that have some special, I have some special property, you use filter to do that, and if you want to manipulate those numbers, you want to multiply them by two of you, use not to do that, you don't have to, you don't have to write for loops, but you have this specialized, not fault, fault field, that are, at least in the C-shop there, and in the Chava script, and I think in the Chava, Chava there's some elements of those two, I haven't been writing Chava in long, long time, so one thing is, yes, that it makes code very concise, it makes it very, it states very clearly, but you are, but you are after, you don't have to think that, okay, here's a loop, and then you are, this is the, this is the variable that goes from zero to length of the list, minus one, and here's, it's incremented, and here's what I'm doing with the thing, it's more about stating that I'm going to, if you see that, you know, that hey, this is going to run a function on a structure, each element of the structure producing on this structure, and if you see field, you immediately know that, okay, this is going to take the same element out of that structure, so let's do right, it states more precisely, more clearly, what you are about to do, or what the code is about, but of course there's more to remember, you have to remember names of those specialized functions, there's some, some friculty-dipit that I did not know where to put this, like, has a non-strict language, meaning that the values are not evaluated until they are needed, or they are explicitly forced, this means that you can, for example, have a, you can easily define, for example, infinite list, and infinite list of numbers, for example, you can say that this list contains all the numbers, all, all, that was all indexes in the universe, starting from the one, and ending up the infinity, and you can start operating with that, you can say that, okay, this another is this, that all numbers will be applied by two, and then this is, all the numbers that are left and hand-tracks, and you can easily manipulate infinite data structures without needing infinite amount of memory and infinite amount of time, because when you define an infinite list, you are only getting the first element of the list, and the rest of the list has not been calculated, when you, for, when you touch the second element, then that one is calculated, but rest, rest is the, right, it's a, it is there, but it hasn't been calculated, it is a saspa, fang, or promise, that it will be there if you request that, of course, you have to remember that you are dealing with infinite things if you are doing this, and don't, don't, for example, try to get the length of the list, because you will run out of time of memory, probably memory, and this also means that the recursion doesn't float stuck, it might lead into, in some cases, it might lead into big memory usage, if you are not careful with you, do things that are untensible, and here is something that sometimes it's hard to read about the performance or memory impact of a program, because everything is, almost everything, you can mark things that, when, when it is encountered, force the value of it immediately, but almost everything is non-strict, so it's a bit hard to, sometimes, think about what the program is actually doing, but on the other hand, in a hospital, the programs tend to be more about what something is, not how some algorithm is implemented, you are, they are, they are so short, and they are, so to the point that with higher abstraction, that they, at least to me, it, it, it, it is more about, the name right in hospital, it's more about, describing what something is, instead of how something is calculated, like I said, the functions are pure, sicknesses will explicitly tell you what, what is going on, they won't, they won't be a nasty surprises on the line, or rather they will, they will be less nasty surprises don't line, of course, if you have a function that has a, that isn't total, but might return a, might not have a value for some combination of parameters, that cannot be expressed in the type level, in the biopsyc nature, you, you either have to know that, or you, you have to find out out in a hard way, there's a type in inference, like in the compiler, can tell you, when, when you have had a compiler, a working Haskell program without type, it will figure out those types by itself, usually, sometimes it does not work, sometimes it needs help, but, for example, inside of a function, you usually don't have to specify bytes, it is a good habit of specifying bytes at the top level, like tell what signature of every function is, because it makes finding errors a lot easier, the compiler is really helpful, if you are, if you miss a case, you know, case expression, it will tell you that your case expression doesn't, doesn't handle this particular case, so we said it there, it's a warning, though, it's not an error, unless you explicitly, the, the, make it an error, same thing with the, assimilating with the imports, if you import a couple functions from a module, and then you try to use some, another function from that imported module, you get a compilation error, and the compiler, we actually said, say that hey, part of it, you mean this one, this looks like what you might have been after. There's a, carrying and partial application, meaning that this, this didn't sound a big thing to me, but it's a huge thing in functional program, it's a, if you call a function of two parameters, with a one parameter, you don't actually get an error, you get a new function pack, you get a pack of function, that it's a, expect one function, and that works, identical to the original function, if the original function had the first, first value find, or fixed to the value you applied, and I, I, I, I use this all the time, it makes writing code really, really pleasant, there's tons of libraries, and some of them have, have really high level of, high level of abstraction, meaning that they are a bit hard to get into, like, you, I often think when, when moving some library, but in Earth could I use this for, because it, it's just so high level, and then has to go hunting, for example, to realize that, what's the actual use case, but when I get to, get to understand the, what the, the problem, library tries to solve, then it's easier sailing from there, or, okay, so, I'll probably over, I'm about to emphasize something, or miss something, but the main thing for me is, when writing has to go, is that it's different language from what I have learned before, and it teaches me, something new about programming, that's, that's the reason I'm, I'm learning it, it's really great and elegant, and interesting language, but those are secondary to me. So, if you had any questions, comments on use, please let me know, you can reach me by email, or you can reach me at the river, so you have to tour to Amsterdam, that's also, or even better, you can record your own episode and have me do the hack-a-fabric radio. Okay, this is to tour to, thanks for listening, have a nice day. Find out how easy it really is. Hack-a-fabric radio was founded by the Digital Dove Pound and the Infonomicon Computer Club, and it's part of the binary revolution at binrev.com. If you have comments on today's show, please email the host directly, leave a comment on the website, or record a follow-up episode yourself, unless otherwise status, today's show is released on the creative comments, attribution, share a light, 3.0 license.