Initial commit: HPR Knowledge Base MCP Server
- MCP server with stdio transport for local use - Search episodes, transcripts, hosts, and series - 4,511 episodes with metadata and transcripts - Data loader with in-memory JSON storage 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
271
hpr_transcripts/hpr2838.txt
Normal file
271
hpr_transcripts/hpr2838.txt
Normal file
@@ -0,0 +1,271 @@
|
||||
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.
|
||||
Reference in New Issue
Block a user