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:
227
hpr_transcripts/hpr2778.txt
Normal file
227
hpr_transcripts/hpr2778.txt
Normal file
@@ -0,0 +1,227 @@
|
||||
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.
|
||||
Reference in New Issue
Block a user