Files
Lee Hanken 7c8efd2228 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>
2025-10-26 10:54:13 +00:00

228 lines
19 KiB
Plaintext

Episode: 2778
Title: HPR2778: Functor and applicative in Haskell
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr2778/hpr2778.mp3
Transcribed: 2025-10-19 16:43:23
---
This is HBR episode 2007-178 entitled, Functor Unapplicative in Hakell.
It is hosted by Tuku Toroto and is about 31 minutes long and carrying a clean flag.
The summary is brief introduction on Functor Unapplicative pattern in Hakell and where they can be used.
This episode of HBR is brought to you by AnanasThost.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 AnanasThost.com.
Hello, you're listening to Hakell from The Cradle and this is Tuku Toroto.
Today I'm going to do a short episode about two patterns in Hakell called Functor Unapplicative.
These two seem to be popping up all the time while I had you working on my 4x space game.
So the first one, Functor. Functor is basically just a way to apply a function over a structure
that we don't want to out. And it's one of the most common structures to do that is a list.
But there are plenty of others and you can even define your own if you feel so inclined.
So the Functor is basically defined as one function and that is called Fmap.
And Fmap has a start signature that takes two parameters.
First one is a function from A to B and the second one is a Struxo F containing A.
And the result is a Struxo F containing B. So if you have a look at the show notes,
I have written the definition there. So Fmap, open parents, A, R, O, B, close parents,
R, O, F, I, R, O, F, B. And F here is the Struxo and A and B are the value inside of the structure.
F i is the starting, starting structure and F B is the resulting structure.
And the A, R, O, B is the function that takes a parameter of A and returns B.
So it's a very general look and it is very, very general, serialized.
So if we use this, like I said, the list is one of the most common examples.
So we can write, for example, Fmap, open parent slash X, R, O, X times X, close parents.
So this is the applying function that doubles its parameter.
And the last parameter is an open bracket of 1, 2, 3, 4, 5, close bracket.
So we are applying a function that doubles its parameter to a list of indexes from one to
five. And the result of this one is a list of 1, 4, 9, 16, 25. So that's basically all the
days into the super, super simple. They just gave it a name so that you will have to always
tell that what you are doing, explain it. I mean, you could just say that you're just
f mapping over some structure. So in the previous example, when we doubled the value
in a list, the type state the same. So we started with the indexes and we ended up with the
indexes. But because the Fmap is from FIFR to FB, we can change the type. So if we were to Fmap
show on the same list again, we would get a list of strings of 1, 2, 3, 4 and 4.
So here we changed the pipe of the end result. But the amount of items inside of the list does
not change. It's always the same. So while you can change the data or the type of the data
inside of the structure, you cannot change the shape of the structure. It's always the same.
And as I said earlier, this is not limited only to the list. There are many other different
kinds of functors. But the pattern is always the same. There's this single, single function
Fmap that takes up two parameters of function and of hunger and our structure A.
And it will return you as structure of B. And the details how that is handled depends on the
specific functor. I hope you can tell the difference between functor and function with my
pronunciation. Okay, another common one is maybe. This is used in the cases where the
data might or might not be present. So you have a, if you have a maybe int, that means that it can
be either just some index value or nothing. There's two cases now. But the Fmap works on this.
So if you are nothing, we have that function that doubles. Let's call it double.
We have that function that doubles its argument, value of its argument. So if we Fmap,
Fmap, double, dollar, just two, we get just for that. So we are using the exact same function that
we used to double the elements in a list. But now we are using it to the maybe int and we are
getting a value tag that has been doubled from just two to just four. If we have a case where the
data isn't present for some reason, we try to load it in the database or that has been a some
validation that decided that it's not valid data or something. We have nothing.
So it's a pattern. Fmap, double, nothing. We get nothing. We don't get error. We don't have to check
if the data is available or not. We just Fmap or it and let the functor handle the details.
This is pretty nice in my opinion.
One more. I'm not going to draw all of these. Let's show many of these. I want to draw one more.
This is a EIDA. This is sometimes used when the value tend to correct.
Or they might be an error. So it has two value constructions. Same as with the maybe int. Now we have
EIDA int and it has two cases. It can have right int that indicates that the
value is correct. Or it can have left int indicating. Left be indicating that the B is incorrect.
And here, actually, sorry, I made a slight mistake. EIDA has a two, EIDA has a type has a two
parameter. So it's EIDA int string. Actually, EIDA string int meaning that it can have
in this example, it can have either the string value or the int value. And
string value is the error case and int value is the correct case. So we can have
for example if you're dealing with some distance calculation, we can have a case where the distance has been
calculated correctly. That's a right file. And if this has been a fail, we can have a left
correlation mark distance calculation. Say it because of flux capacitor,
monofunction, closed correlation mark. So our EIDA string int can have two
these. Two these have these two types of values. So can you guess what happens if we
not over that? If we fmap, let's say it's a little too, no, actually, no, let's not. So we fmap
double over right five. So fmap double dollar right five. And we get right 25. And then we fmap
double dollar left distance calculation failed because of flux capacitor error,
the error malfunction. We are getting that left distance calculation failed because of flux
capacitor malfunction. So when you are using fmap to a right value, you are getting a result of
that function applied to the value that is inside of that right fraction. But if you are fmap
in some function to the left value, then you are getting the left value back. It is without any
changes. And this this might throw throw of U because you are using a function that takes
an index to a left string. But it will work. It will just return the left distance calculation
failed because of flux capacitor malfunction. So this this one this pattern can be used in the case
is you have some data and complicated calculations and you are carrying, you want to validate for
example, some points, different points. And you don't want to check all the time that if there has
been some mistake before, you just use the values, value as it comes, you can validate it, you can
do calculations and do more validation. And the result will be right, something if everything
was correct or left, something else, if there was a error along the line and the left that is
been returned is the first left of the well, the only left of course, because after that it just
keeps repeating. And it is even possible to combine these things. So you can have multiple
functions, so for example, you can have maybe a list int, which is already done as a maybe
open bracket, int close bracket. So here we have a list of int that might or might not be possible.
And then you can again, you can reach through all these layers to the list of integers
and see and do your do you operations there. So but because you have a
multiple functions, you have to, you could do it in a way that you first,
well, let's not, well, to reach inside of the through the multipliers of the functions,
you have to do FMAP multiple bands. And this is, there's a handy way of doing that.
So you can have open, open barren FMAP dot FMAP close barren, double open barren just
open bracket 1 comma 2 comma 3 comma 4 close bracket close barren. So instead of FMAP,
we are using FMAP dot FMAP to do the FMAP. Comize a function composition in a Haskell.
So it's basically taking a FMAP and running an FMAP to the result of that first one. So you have
a function here that can given parameters will run FMAP twice. And if you run the example,
you're going to going to get the result of just one, just open bracket 14925, no 16 of course.
So we have double, double doubling the values.
Okay, if we have, if we do the FMAP, sorry, if we do the FMAP dot FMAP dot nothing,
we get the result of nothing of course. Because we did not have the list.
And the last last one is that I want to talk about the here is that you can have a multiple,
if you have multiple functions, the order of how you build your functions of course matter. So if you
have a instead of a maybe list of ins, you can have a list of maybe ins. So type of that would be
a open bracket, maybe in close bracket. And then again, we can just use the FMAP dot FMAP double
open bracket, just one, just do nothing, just really close bracket. And we are going to get the
result of just one, just for nothing, just mine. So our couple function is being applied to the
values, those index values that are inside of maybe is that are inside of list structure. And
yeah, there's an infix operator. Like the FMAP is FMAP function structure,
but the infix operator is just exactly the same thing, but the syntax is a little different,
it's called, well, I don't know if it's a, if it has any specific name, I couldn't find
specific name for this one, if somebody knows I'm gladly here, but it's a, I'm using a dollar
time or a name of this one, because it's a small, a dollar created. So those three characters
together are the infix operator of FMAP. And they do exactly it does exactly the same thing as the FMAP.
So if we do the FMAP show 1, 2, 3, 4, 5 and get a list of strings, 1, 2, 3, 4, 5 as a result,
we can also do the show dollar diamond, 1, 2, 3, 4, 5 and get a list of strings, 1, 2, 3, 4, 5 as a result.
And the choice between of when to use FMAP and when to use the dollar diamond is mostly
what, I don't know if the aesthetic is correct but mostly it doesn't really matter, you can choose
between, between then freely. Sometimes it's easier to write either one of these,
one of these depending on the context of how the, how the, but you are, what you are working,
working it because Haskell doesn't use that many parenthesis, function application doesn't
use any, it doesn't use any parenthesis at all. So sometimes it's easier to use FMAP and sometimes
it is, it is easier to use the dollar diamond. Okay, but like I said, there are many, many, many
other functions and you can define them by yourself if you, if you have a need for that,
I'm included a link into the show notes that list some of those that are available
in different libraries. Okay, now that we deal with the function, we move into the, to the
applicative and this is, this is basically building on, on function, it's even building that much
every applicative is a function, a function. So the function works fine when the function being
applied has only one parameter but in case that you have two or more than it does not really work
anymore and the solution here is the applicative. So applicative defines two, two methods,
two functions, one is pure, that takes a hey and returns a fa. So it takes some value and
impacts it in, it turns it into a structure containing that value and then it has a
asterisk diamond operator or die factor as some call it because if you squint it looks like a
die factor from the Star Wars, advent life item event because it has those paintings but that
operator is smaller than asterisk created than those three characters together is the operator
and it looks quite a bit like the F map in the, or the actually the dollar diamond in the
function. So when the F map was that it takes a function from A to B, structure, F, A,
antigens, F, B, then the function applicative takes up A, B, inside of that
structure. So it's a S, open turns, A, R, O, B, goes, burns, then R, O, F, I, being this
A inside of the structure and result result is a S, B, so B inside of the
structure. So it's similar to function except the function being applied is also embedded inside of that
structure. So why would you want to do that? Impact the function inside of the structure.
So some examples might clarify this a bit. If we have a, for example, plus operator and we
add a F map that over a list of integrals, we get a list of functions because the plus operator
accepts two parameters. And in the, in the husk, if you are, if you are husk, that's a
partial application, carrying, automatically. So if you are, if you were to apply a, let's
forget the applicative and functions for a second. If you were applied a plus function to a
single parameter one. So plus one, you get a pack, not a syntax error, but you get a pack
function of that takes a one parameter, one in parameter. And that functions, function acts
one to that parameter that you pass it. So it, it works in a, like that the original function that
you called with a single parameter, didn't a function that has the first parameter fixed
towards what you passed in and it's expecting the second parameter. And when you have
a second parameter, it does the calculation. And this means that if you are F map plus
to a list of integrals, you get a pack, a list of functions that are waiting for the second parameter.
It is possible to do it manually, take one or each of those functions and call them. But
it would require a little bit of work and it would require a little bit of different kind of work
depending on of the case. If you have a maybe, or if you have a list, you wait to reach to those
functions a little bit different. And we don't want to do that. We want that. We like to have
general way of doing that. And that's where the applicative and the asterisk kind of
operator comes in. So if the F map plus function over a list of in in one, two, three. And then
to that result, we do the asterisk diamond. And at least four, five, six, we get a list of
in five, six, seven, six, seven, eight, seven, eight, nine. So that happened here.
The F map gave us a list of functions, three functions waiting for the second parameter.
And when we when we use the asterisk diamond, four, five, six, to that, the applicative
automatically calculated. It called took the first function and used that to call all these three
values. Inside the second list, we fasted it, took the second function, called those three values
and took the third function and called those three values. So this is a way we can
tell the household to yes to list of in please something all together, like all them together,
not first and first of each list and second of each list and third of each list.
That's a way of doing that, but that's not how the applicative instance of the list that has that.
So in essence, there list applicative calculates all positive combinations and I don't
have to use it, but I would imagine that this might be a handy if you are doing some calculation
that are doing prediction and you're not quite sure about the parameters. You have
you have some calculation and you have some uncertainty in the parameters there. So you can
you could do it in a way that you give a couple of different values to those parameters and do
the calculation and keep doing the calculation in every case where you have.
Uncertainty you give a parameters from the range and then the list applicative will make sure that
in the end you get all possible results back. Then you could do some statistical analysis to
maybe draw a histogram or something and see what is the most likely one and what is the maximum
one or what is the minimum one or what not.
Okay, and if you are doing the and this of course is not
limited to the list because you have applicatives for other things. For example, just
sorry, maybe. So again, we are doing a if you are calculating some of
two integers that might or might not be present. We can do open parent plus close parent.
This is a plus plus symbol. A plus function basically took the infix of
infix operator plus and third into a function.
A dollar diamond just two are asterix diamond just five and we get back result just seven.
So two plus five is seven and in the case when we don't have one of the values if you do the
plus dollar band just two asterix diamond nothing we get the result of nothing.
Again, this is what I like here. I don't have to do any kind of checks if the value is present
or not the applicatives and some will take care of that for me.
No, if checks no null checks nothing which is I just said that I have these two values that
might or might not be present calculate them together and give me the result. If the value is
present I get the result and if the some one or more value is present present
as nothing I get a nothing back. So the dollar diamond is using combination with function.
So it's usually at least I usually use the asterix diamond is used in combination of
function. So usually I use the dollar diamond to get started. So I get partial
outside function inside of that structure if whatever it is in that case and then I use the
asterix diamond to further apply it with more parameters until I get the enter result back.
You could use the pure that takes one value and ended into a structure to get started but
I did not do that. Okay, that's about it. Two super common patterns that turn up in the
Huskel all the time and that have names that don't really mean anything to you until you read about
them or somebody explains them to me. To be the probably hardest part about learning the Huskel
is not the syntax or the how the programs are constructed like the functional and that you
cannot mutate value so those did have some learning curve but it was not as deep as I expected
them to be. The steepest one has been to learn about all these patterns that have names that I
have not heard before and learning about them, learning how to use them and when to use them
and learning even about learning things, the existence. I'm not sure if there's a top 50 list of
Huskel or top 10 list of Huskel patterns you ought to learn when you get started with learning the
Huskel. But if you have any questions or comments please send them to me. I have a email address
at the show notes and you can also read me at the peripherals and the tutorial at master.on.social
or even at the recursion on Haga Public Radio episode. Okay, Ad Astra.
You've been listening to Haga Public Radio at Haga Public Radio dot org. We are a community podcast
network that releases shows every weekday Monday through Friday. Today's show, like all our shows,
was contributed by an HPR listener like yourself. If you ever thought of recording a podcast
then click on our contribute link to find out how easy it really is. Haga Public Radio was found
by the digital dog 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 like, 3.0 license.