- 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>
450 lines
16 KiB
Plaintext
450 lines
16 KiB
Plaintext
Episode: 2808
|
|
Title: HPR2808: Haskell function types
|
|
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr2808/hpr2808.mp3
|
|
Transcribed: 2025-10-19 17:05:18
|
|
|
|
---
|
|
|
|
This is an HPR episode 2008 and 2008 entitled Haskell Function Types.
|
|
It is hosted by Tuku Toroto and is about 24 minutes long and carrying a clean flag.
|
|
The summary is Tuku Toroto gives over new Function Types in Haskell.
|
|
This episode of HPR is brought to you by an honesthost.com.
|
|
Get 15% discount on all shared hosting with the offer code HPR15.
|
|
That's HPR15.
|
|
Better web hosting that's honest and fair at An Honesthost.com.
|
|
Hello, this is Tuku Tuku Toroto and you are listening to the HAKER POTTER CRADY.
|
|
Today's episode will be about Function Signatures in Haskell.
|
|
Again, this is something that I should have done ages ago.
|
|
But once again, better late than never.
|
|
So Haskell is a static language, which means that when it's compiled, the compiler checks the program for type errors.
|
|
So, it makes sure that you are not mixing for example strings and numbers.
|
|
And for that, it needs types.
|
|
Type is a definition of what kind of values can be used.
|
|
Typical ones are in the string, text, bool and so on.
|
|
There's quite a lot of them in the Haskell.
|
|
And of course, new ones can be defined by the programmer.
|
|
And type names always start with the upper case level.
|
|
So then Haskell does type inference, meaning that if you choose so,
|
|
you can omit type declarations completely.
|
|
You don't have to tell Haskell that type of this function is something.
|
|
You just can omit those completely and Haskell will try and figure out what kind of types would work for that.
|
|
But it's helpful for the programmers if you are writing type declarations out.
|
|
Because then they can more easily check from the source code.
|
|
But what kind of type some function takes.
|
|
And also, it instructs Haskell compiler that this function should have these types.
|
|
Otherwise, if you don't specify that, Haskell will try to figure out what's the type signature.
|
|
Sometimes it works, usually it works.
|
|
But at the point where you make a mistake, then the Haskell compiler will try to figure out the type
|
|
and it might give you a compiler error somewhere completely different place.
|
|
So you should write type declarations at the top level of your program,
|
|
meaning that all your functions should have types in them.
|
|
And the type declaration is written as a name of the function.
|
|
And colon, colon, and then types that it takes.
|
|
So, for example, the simple, I won't be talking that much about the code in this,
|
|
this, this or that will be talking more about the signatures.
|
|
And what are the things you can do with those and what they tell you about the functions.
|
|
So the simple, simple case is that you could have a function called add,
|
|
that takes an index, two integrals, and produces an integer.
|
|
And this is, as a type declaration, that declaration is written on top of the function,
|
|
function definition.
|
|
So that declaration for this type of function will be add, colon, colon,
|
|
integer, arrow, integer, arrow, integer.
|
|
So it takes two integrals and it produces value of inverter.
|
|
And you don't have to have specific types.
|
|
Sometimes you can have, you can mark that anything calls here.
|
|
For example, if you had one another made up example,
|
|
you would have a function that has signature of choose, colon, colon,
|
|
a, arrow, a, arrow, bullen, arrow, a, and a is a lower case here.
|
|
So, it, that means that this function choose takes two values of type a,
|
|
which can be anything, a bullen, and it will produce a value of a.
|
|
And a is always the same type in this function.
|
|
It can be anything, but it's always the same in, like you cannot mix,
|
|
you're going to put different types in the a.
|
|
And we don't know anything about the a.
|
|
It can be absolutely anything, which means that we also can do much inside
|
|
in the true, of choose function with the a.
|
|
Basically, we add even two a's and bullen,
|
|
and based on that bullen, we are returning in the line of those a's.
|
|
So, if we want to add a bit more functionality in that case,
|
|
in a case where we don't have a specific type,
|
|
we can use something called a bullen morphism.
|
|
So, if you remember the at function,
|
|
that we mentioned a couple of minutes ago,
|
|
it only works, it only works within that case.
|
|
You cannot use it with the float.
|
|
You would, of course, define add f, that works with the float,
|
|
and then some add i that works with the imaginary numbers and so on.
|
|
But it would be kind of silly,
|
|
because then the programmer would have to remember that
|
|
here I'm adding in that, so I have to use add and here I'm using float,
|
|
so I have to use add f.
|
|
So, we can define that by using a type constraint.
|
|
That means that we are writing it,
|
|
the signatures would be add colon colon, open current,
|
|
uppercase num, over this a, closed current,
|
|
sad arrow, a, arrow a, arrow a.
|
|
So, this means that a is constrained to be an instance of num,
|
|
and add function takes two a's and produces a.
|
|
And num in this case is a by-class that defines some functions
|
|
that every instance of num implements.
|
|
So, you know that if you are given, if your function takes an a,
|
|
you don't know, you don't know exactly what it is.
|
|
But you know that because it's a num,
|
|
it has some functions that you can use on it.
|
|
And num defines plus, minus,
|
|
multiply, multiplication, negate, ups, sigma, and from index.
|
|
So, it's some very, very basic number type of arithmetic.
|
|
And I'm going to talk about type classes,
|
|
another time that really need a concept,
|
|
but grabbing them into this episode will make this a bit too long, I think.
|
|
So, if you have a by-constraint,
|
|
that is an uppercase num a, sad arrow,
|
|
means that everything, everything in the type,
|
|
the type signature a is always a num.
|
|
And you can have, of course, multiple type constraints.
|
|
You can say that num could be num.
|
|
You could say that a has multiple constraints,
|
|
or you could have that something that a is constrained
|
|
to something and b is constrained to something.
|
|
And we are not using b in this case, but you can have multiple,
|
|
multiple type parameters.
|
|
So, that is how you can use pretty generalized functions.
|
|
And the cool thing is that our num,
|
|
our ad function will work for every num instance.
|
|
So, if somebody comes with a new data type,
|
|
that implements, that has an in-the-instance num,
|
|
our function will work with that, no problem.
|
|
If, okay, if that num instance is written properly.
|
|
Okay, then you can have parameterized functions,
|
|
like, for example, you could have a function called first,
|
|
that has a signature, signature of first,
|
|
colon colon, open bracket a closed bracket, arrow may be a.
|
|
And this is a function then that takes a list of a,
|
|
that's the a inside of brackets.
|
|
And a, again, can be anything.
|
|
And it returns may be a.
|
|
I talk about maybe in an early episode,
|
|
with this type that is used to signify,
|
|
value that might not be present.
|
|
So, a can be anything, again.
|
|
So, you are given a list of a's
|
|
and it returns may be an a.
|
|
And may be an a can be nothing or just a.
|
|
So, in case you are given a list of,
|
|
that is, at least one element,
|
|
this will presume to,
|
|
presumably, return the first element of that list.
|
|
That's just a.
|
|
But if you are given an empty list,
|
|
this wouldn't crash,
|
|
but it would just return nothing.
|
|
And if you want to use functions,
|
|
again, this is something really basic
|
|
that I should have brought up,
|
|
this would have told ages ago.
|
|
But when you are calling or applying a function,
|
|
you don't need parenthesis.
|
|
So, our at function can be called,
|
|
just try to simply add one to.
|
|
So, you don't need parenthesis.
|
|
And this means, of course,
|
|
that if you are changing functions,
|
|
like you are, for example,
|
|
you are calling one,
|
|
you want to add more things.
|
|
You can write it as a,
|
|
add one dollar sign,
|
|
add two, three.
|
|
And the dollar sign is there for the application order.
|
|
It instructs that,
|
|
first you evaluate the right side,
|
|
add two and three,
|
|
and then you use that value
|
|
in the evaluation of the left side,
|
|
at one.
|
|
So, you are basically,
|
|
you could use parenthesis,
|
|
you could write that in the,
|
|
you know, add one,
|
|
open parenthesis,
|
|
add two, three,
|
|
close parenthesis,
|
|
and the result will be identical.
|
|
Six in both cases.
|
|
And it's a, again,
|
|
a bit of a personal preference,
|
|
which one?
|
|
You two use,
|
|
I usually opt for using,
|
|
a lot of times.
|
|
Sometimes,
|
|
it is easier to parenthesis.
|
|
But it's good to know that there are options.
|
|
And there's a one thing that really
|
|
took some time to get used for me,
|
|
is that you don't use parenthesis at all,
|
|
in a function call.
|
|
You just write the function name,
|
|
and then you write the parameters.
|
|
There's a,
|
|
another need,
|
|
concept in Haskell is the
|
|
part of the application.
|
|
So, you can,
|
|
you can call function
|
|
with less parameters,
|
|
that it expects,
|
|
and it won't cause,
|
|
it won't cause a runtime error.
|
|
So, example, you could define.
|
|
If we have defined that,
|
|
add function,
|
|
we could define another function.
|
|
Say, add lots,
|
|
equal at thousand.
|
|
So, we are calling add,
|
|
our add function,
|
|
that it's set two parameters,
|
|
the single parameter.
|
|
What happens here,
|
|
is that,
|
|
it will automatically,
|
|
generate us a,
|
|
when you're calling add,
|
|
with the set a single parameter,
|
|
instead of runtime error,
|
|
we are going to get a new function back.
|
|
And this function works,
|
|
exactly like,
|
|
add function,
|
|
with the,
|
|
that has been,
|
|
that has the first parameter,
|
|
thousand.
|
|
So, now that we have,
|
|
our add lots,
|
|
that equals to add thousand,
|
|
we can use our add lots to,
|
|
just call add lots five.
|
|
And this is equal to calling,
|
|
add thousand five.
|
|
So, you can easily,
|
|
easily create new functions.
|
|
And,
|
|
for example,
|
|
sometimes I like to use this,
|
|
in a way that,
|
|
I have some,
|
|
general function,
|
|
that takes our,
|
|
some sort of configuration,
|
|
and then some,
|
|
some sort of parameters,
|
|
that instructs,
|
|
that uses,
|
|
and then,
|
|
that parameter,
|
|
configuration results,
|
|
to some value.
|
|
For example,
|
|
if I have a,
|
|
if I had a game,
|
|
where you have a building,
|
|
and I wanted to know,
|
|
a cost of a building,
|
|
I would have a,
|
|
general function,
|
|
that would have a,
|
|
list of those building costs,
|
|
and then it would take a,
|
|
name of the building,
|
|
and result would be the cost of the building,
|
|
it would call,
|
|
through the list,
|
|
find the building,
|
|
return the cost of the building.
|
|
I can use,
|
|
this partial application,
|
|
to create a,
|
|
function,
|
|
that takes the,
|
|
general configuration,
|
|
that is used in everywhere in the program,
|
|
and afterwards,
|
|
I have to test that,
|
|
configuration,
|
|
into the function name,
|
|
or,
|
|
because I have that,
|
|
new function,
|
|
that has been,
|
|
sort of configured,
|
|
to use,
|
|
that,
|
|
list of buildings.
|
|
So I can just call,
|
|
that,
|
|
new function,
|
|
with,
|
|
name of the building,
|
|
and it will give me,
|
|
the cost of the building.
|
|
Completely made up,
|
|
explanation,
|
|
but,
|
|
that's,
|
|
that's a one,
|
|
one way,
|
|
I could use this.
|
|
And this,
|
|
this is called,
|
|
carrying,
|
|
so,
|
|
Wikipedia says that,
|
|
in mathematics,
|
|
and computer science,
|
|
carrying is the technique,
|
|
of translating,
|
|
the evaluation,
|
|
of a function,
|
|
that takes multiple arguments,
|
|
into evaluating,
|
|
a sequence of functions,
|
|
each,
|
|
with a single argument.
|
|
There was some,
|
|
mathematics,
|
|
mathematics and code,
|
|
I think,
|
|
I think he was called,
|
|
Howard Curry,
|
|
who,
|
|
came up with this,
|
|
and,
|
|
a bit earlier,
|
|
some,
|
|
another mathematics and code,
|
|
search single,
|
|
came up with,
|
|
the same idea.
|
|
So,
|
|
if,
|
|
if the,
|
|
Curry wouldn't have,
|
|
I don't know why,
|
|
it's the,
|
|
why,
|
|
why, this is,
|
|
named as,
|
|
Curry,
|
|
Howard Curry,
|
|
because,
|
|
if it were,
|
|
named after him,
|
|
we would,
|
|
we wouldn't be called,
|
|
talking about,
|
|
thinking,
|
|
which,
|
|
I think it would,
|
|
yeah,
|
|
funny,
|
|
but, in any case,
|
|
you can do part of your application,
|
|
and,
|
|
the,
|
|
all of the parameters matter,
|
|
as they are evaluated,
|
|
from left to right.
|
|
So,
|
|
some,
|
|
sometimes,
|
|
it makes sense,
|
|
to,
|
|
dig the,
|
|
parameter,
|
|
order,
|
|
a bit more,
|
|
then,
|
|
then,
|
|
you,
|
|
then,
|
|
what I,
|
|
was used to,
|
|
according without,
|
|
another images,
|
|
because,
|
|
if you have to,
|
|
always,
|
|
fly all the parameters,
|
|
you don't,
|
|
the order of the parameters doesn't really matter,
|
|
but,
|
|
here,
|
|
because you don't have to,
|
|
fly all the parameters,
|
|
then,
|
|
order start mattering a bit more.
|
|
For example,
|
|
if I had a,
|
|
function plant broadcast,
|
|
that take a list of broadcasts,
|
|
auto and produces a list of portcasts. I could if that function is called find
|
|
portcasts. So find portcast has a signature of list of portcasts text list of
|
|
portcasts. So I could define a new function called search that equals to find
|
|
portcast, loaded portcasts, loaded portcasts, a list of portcasts that came from
|
|
some way, not in part of some way. And then I could use that function as a my
|
|
portcast equals search to turbo. And that would search from that original list of
|
|
portcasts, all the portcasts are made by me. But if the parameter order would be
|
|
other way around in the find portcast function, it would first take the name and
|
|
then the list of the portcasts, this method group verb. Okay, and then functions
|
|
as types. Functions themselves are also types. So and they can be used as values. So
|
|
you can you have if you have a function, it can be done a function and if you
|
|
have a function and also a function can take another function as a parameter. One
|
|
very common function that task is a filter. And it has a signature of filter,
|
|
colon colon, open turns, R a, arrow, rule, close turns, arrow, open bracket,
|
|
A, close bracket, arrow, open bracket. I'm sorry, let me do that again. So filter has
|
|
a signature of filter, colon colon, open turns, A, arrow, rule, close turns, arrow,
|
|
open bracket, A, close bracket, arrow, open bracket, A, close bracket. So filter is a
|
|
function that takes two parameters. First parameter is a function that has type of A,
|
|
arrow, rule. And the second parameter is a list of A. And it will return a list of
|
|
A. So you need to have a two functions that have a
|
|
maxing A. A can be anything, but it has to be same on both of those functions in the
|
|
filter and in and in that parameter that filter breaks. And what the filter does is that it
|
|
will apply that function that was given to every element in the list. And for every element
|
|
that evaluates to, for every element that the function evaluates to true, it will return
|
|
as a new list. So it has a name implies it is used to filter a list with a given function.
|
|
It will find all the functions, all the elements in the list that will return true when given
|
|
to that parameter function. You can use that for example, writing a filter, hot, open
|
|
bracket, one dot dot, then close bracket. This will produce a list of hot numbers in a
|
|
range of one to ten. And the last thing I'm going to call it today is the anonymous functions.
|
|
Sometimes you need function to pass in as a parameter, like in the previous case, but you
|
|
don't want to define and give it a name. What be that you are going to use it only once,
|
|
or it is so short that it does not really need a name, it doesn't run having a name. So
|
|
photos cases we have a long dot, or anonymous functions. And the syntax is for one function.
|
|
It is a, for example, if you are going to use in the filtering example previously, we
|
|
will want to filter all the hot numbers that are picket and file. We could write it in a
|
|
following way. Filter, open parent, slash x, arrow, hot, x, ampersand, ampersand, x created
|
|
then five, close parent, open bracket, one dot dot, then close bracket. So here we are, here
|
|
we will be defining an anonymous function that takes a single parameter, x, and checks
|
|
that the x is hot, and that x is created and five. If those both are true, then the value
|
|
of the function is true, and this we use to filter all the hot numbers created and five
|
|
in a range from one to ten. And you don't have to specify types here, has can will figure
|
|
them out for you. So the syntax is a slash parameters, arrow and body, and you can have multiple
|
|
parameters in the function. There are just separated by the spaces. And often you have
|
|
to wrap this thing, you know, parenthesis when you're passing it in so that the hospital
|
|
compiler knows where the anonymous function starts and where they pay it ends. Okay, that's
|
|
it for today. If you have any questions or comments or corrections, easy way of catching
|
|
me is either email or at the fediverse where I'm to tour at masterton.so also, or you
|
|
can even, even better you can make your own hack-a-pattered radio episode. Okay, thank you
|
|
for listening. Bye-bye.
|
|
You've been listening to hack-a-pattered radio at hack-a-pattered radio.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 contributing to find out how easy it really is.
|
|
Hack-a-pattered radio was founded by the Digital Dove Pound and the Infonomicon Computer Club,
|
|
and is 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,
|
|
distribution, share a light, 3.0 license.
|