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:
Lee Hanken
2025-10-26 10:54:13 +00:00
commit 7c8efd2228
4494 changed files with 1705541 additions and 0 deletions

338
hpr_transcripts/hpr2788.txt Normal file
View File

@@ -0,0 +1,338 @@
Episode: 2788
Title: HPR2788: Looping in Haskell
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr2788/hpr2788.mp3
Transcribed: 2025-10-19 16:51:35
---
This is an HBR episode 2007-188 entitled Looping in Harkel.
It is hosted by Tuku Toroto and in about 47 minutes long and Karima Clean Flag.
The summary is, Tuku Toroto describes some loop-like constructs in Harkel.
This episode of HPR is brought to you by archive.org.
Support universal access to all knowledge by heading over to archive.org
forward slash donate.
Support universal access to all knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge,
Support universal access to all knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge, knowledge and knowledge, knowledge, knowledge, knowledge and knowledge, knowledge, knowledge, knowledge and knowledge and knowledge Kultur.
functional programming and all the data in it is immutable which means that once you have
said that value of something is something that value will never ever change anymore
and that makes our having a regular four loops pretty hard because you don't have a
value that increments in each of each loop but looping is still very essential for programming so
there's a different kinds of patterns for specific cases in Haskell in you know general sense there's
a couple three maybe main types of loops and if you're looping through a list one is that you
are modifying values another one is that you are taking some of the values from the list and putting
them in another list and third one is that you are using all those values to calculate some end
value and if you have a in a certain still in general sense if you have a loop from end to
end and do some calculation based on that it's essence is the same as looping over an array or
list that has numbers from end to end so the first two and that is usually thought is
recursion and there's many many kinds of many different ways of doing recursion in Haskell
and one of the canonical hello bird examples in Haskell is calculating Siponacci numbers this is
a sequence of numbers that show up in a nature quite quite often in very very many different
places for example the self-lower seed in the kernel formed Siponacci pattern but so it's a it's
a sequence of numbers the every number is the sum of the two previous ones so it starts like
0 1 1 2 3 5 and so on so the first first way of calculating that is the doing the
just a regular regular recursion and if we have a function called Sipz that takes a
and produces in the config and provides three cases for this fit 0 equals 0 this is the
one of terminal cases so whenever you call this function with a value 0 you will get 0 back
and then fit 1 equals 1 meaning that whenever you call this function with a 1 you get 1 back
these two are the starting values that you cannot calculate this on the previous one values
then is the general case Sipz n equals Sipz open bracket n minus 1 close bracket plus Sipz open
bracket n minus 2 close bracket and this will calculate that if you put a number that doesn't
match on the any of those two previous cases so it isn't greater than 1 it will first calculate
the Siponacci number that is n 1 that is from the that you get a new minus a minus 1 from the
n so Fib's n minus 1 is the previous Siponacci number and then you sum it with the Fib's n minus 2
which is the one before the previous Siponacci number so this will if you put 3 sorry if you put
2 in this this function will calculate Fib's 1 plus Fib's 0 and those matches to the two previous
cases and you get value of 1 if you put 3 you will get Fib's 2 plus Fib's 1 which is
now I have to calculate actually then you are getting a 2 so this has been defined if you
have been defined in the terms of recursion and this is a this works really well for the small numbers
but if you if you want to calculate a big Fibonacci number then the recursive value of doing that
because it will calculate all the numbers before this multiple times even because if you have a
Siponacci if you're going that this with the 10 then it will calculate you in order to calculate
what's the 10 number it has to calculate 9 and 8 and in order to calculate the 9 it has to
calculate 8 and 7 and in order to calculate the 8 you have to calculate 76 so it will it will
calculate numbers previous numbers multiple time even to get the final answer so while this is a
easy to follow example it almost looks like the mathematical definition of Fibonacci sequence
as Fibonacci numbers it is really slow there's a faster ways of calculating these things but some of those
are really get really really matchy and I'm not going to talk about those I might I'll try to
remember to include a link into the show notes for the page that has multiple ways of doing this
another way that uses the recursion is to calculate them in the instead of calculating a specific one
is to define but what what all Fibonacci numbers are we just define a list of indexes
and in Haskell there's an operator colon so that on the left side is a value on the right side
is a list and it produces a list where the first element is the value and rest of the list is
up and that behind of it and it's that's what we that's what we are going to use here there's also
a function called chip fit that takes up function and two lists and it produces a new list that has
been that has been created by taking first elements of those lists using them with that function
and then taking second elements of both lists and using those with the function and so on
so that's where the name comes comes from chip fit it's like a cheaper that combines two lists
one so now that we know those we can define a all Fibonacci numbers and this is all Fibs
equals zero colon one colon chip fit open bracket plus close bracket all Fibs open bracket
tail all Fibs close bracket and that's it so what that what does this two is define a list
that the first element is zero second element is one and rest is a list that you get when you take
this list that you that we are defining and chip that with plus so you're summing the elements
you take the all Fibs which is the whole list and then you take tail of the all Fibs which is
everything but the first element so the third element of the list is zero plus one which is
one fourth element of the list is the one plus one which is two and so on and this is really
funny way of in my opinion in my opinion when I mean when I first saw this way of calculating
things I couldn't grab my head around how is this impossible because you are defining a list
in terms of itself and this list is essentially it's infinite it contains all Fibonacci numbers
so if you if you're defining a list like this I isn't it immediately immediately running out
of the memory but this is because Haskell is a non-strict language it evaluates things
as little as usually as little as possible it doesn't evaluate value values until absolutely
necessarily required or if it has or if it's specifically instructed to evaluate something
for example in most programming languages when you are calling a function the function application
first you evaluate the parameters that are going inside of the function and then you evaluate
the result of the function in Haskell if the values that are given as a parameters aren't evaluated
and they are given to the function if if there's a function called a producer value and that
value is given as a parameter like that for example if a function parameter is a function
calling in itself to something that function call isn't evaluated until that parameter is needed
inside of that another function so this this is the reason why you can build an infinite list
of Fibonacci numbers without running out of memory if you were to if you were to print this
out on the console for example then it will it will take a while and you would eventually run
out of the memory but you can always for example take first 100 elements of the list and print those
out and then you are not running out of the memory or you can skip first 10,000 elements and then
take one then you are then you are getting 10,000 first Fibonacci numbers and it's it's really fast
I tried it in my old computer the answer came immediately while in the previous Fibonacci
calculation it didn't I didn't wait until it would have completed
so that's another one of the way of doing a recursion and if you if you if we were to add
if we if we had a list of intercourse and we wanted to add one to each of those lists this this
is a one one moving proofing construct that you're going through a list and adding one to the
elements in hospital you cannot you cannot modify a list you have to create a new one so
so if we had a function called add one that takes a list of intercourse and produces a new list
of intercourse we could define it one way of defining is to say that add one open bracket close
bracket equals open bracket close bracket this is the terminal case again if you have an empty
list and you write one to that you're going to get an empty list and then the second
second case is add one open parent x colon xs close parent equals x plus one colon at one xs
and that's it so what what does this second second definition mean it means that
when you're calling are at one with a list that that yeah when you're calling at one with a
list that has elements on it the x is matched to the first first element on that list and xs
contains rest of the list it might it may be empty list the xs or it may contain
who knows how many how many items but but the thing is that the x is the first element of the
list and xs is the rest of the list and then we then we just say the result of this is x plus
one because we want to add one to each of the list and then we add that to list which we get
by calling at one with xs so basically we are adding one to the first element of the list
and then we are adding a calling recursively the at one with rest of the elements and if there's
a elements left it will go again come come to that second case keep keep adding ones to the
elements until comes a case that there is no any more elements left in the list and it matches
to the first at one definition returns empty list and the whole recursion stops there
you have to remember that if if you write it this way your essentially you are reversing
the list if you have list of one two three and you feed it to this function you're going to get back
for three two but this is one one way of processing of list looping looping over it doing things
and the third pattern is now sorry second pattern that I talked earlier is that you take all these
elements and do something to all of them to produce a new value so if you add a list and you
want to add all elements on each together one way of doing it is to make a list sum or that takes
index list of index and produces index that initial index is the starting value
that we are going to use you could the same we need that to accumulate the rest results
that we are getting when we go through the list so sum or first definition is sum or n open
bracket close bracket equals n so if you have empty list then you are getting the initial value
back the end that was given this is the terminal case this means that the list has been processed
with the original list process at all then the second case is sum or n open parent x colon xs
close parent equals sum or open open parent n plus x close parent xs so this is the
recursion part so if again the open parent x colon xs close parent matches a list
first element of the list and the tail of the list and we calling recursive list them all
and in that accumulator part we are putting n plus x and then items the process we are putting
tail of the list so whatever we have accumulated so far we add to the first element and then we call
to the sum or to the rest of the list so this will go through a list one element of time suming
them up until you get final result in the end and the third pattern that I mentioned is that
you have some elements that you are looping over and you are moving some of those into the
another list of making decisions that just is this an element that I'm interested in
again if we have list of indexes and want to produce a list of even indexes
yet we can do it by following the finish and even only open bracket close bracket equals open
bracket close bracket this is again the terminal case that thing that stops the recursion if we have
an empty list we are producing an empty list then there is the axiologic part even only open
parent x colon xs close parent equals if even x then x colon even only xs else even only xs
meaning even is a function that we have given a number will return the rule and if it's a even number
or not so if x is even then we are returning now that's the starting thing here
have a bug here if we have an event then we will be returning x and then adding no there's no
problem yeah it's morning so okay so if even x so if x is even then x colon a even only xs
so if the x is even then we are returning the x and the rest of the list that we have process
it even only else even only xs so if x isn't even then we are only returning the
the rest of the list that has been processed with even only and this will record recursive
value first go through the list and pick up the numbers from the numbers even numbers from the
list and kind of I have to try and try out that it actually works like I thought it would work
yeah if I call if I call even only with a list from one to six I get back a list from with two
four and six so it works that's the that's the problem with the recursion sometimes that it
might be a bit hard to wrap your head around how how the thing goes how how the logic goes in
it's pretty simple construct but sometimes you just get a mind lock or
and then you're just going like does this really work what's what's going on here but that's why
we have modules because writing recursion by hand gets tedious and sometimes it's hard to follow if
you're not used to that so and we like to abstract common patterns and give them a name because then
you can say that we are going to do things x to this list instead of describing that we are going to
put this as a recursion thing and it's going to work like this so abstracting out common patterns
and giving them names it's easier to talk about those things when you when you know those names and
they are common to meet the people that you are talking to and that's that's a one thing that I
have had to try to put the half gone learning old funny names for these things
so there are many tools of two and two things but following three things will get you started
the first one was you are producing a new list and for that there's a map or in a genera
or even more genera f map but they in case of the list they will work in the same way
so map is a function that takes a function from a to b and a list of a and produces a list of b
a and b can be anything so function that can process the types of items that are in a list and
produces a and that will produce a new list so if we were to add one to a list we could write
that map open terrain plus one close bar and and then the list and that's it we we are going to
apply plus one function to a list of elements and if we are going to call a map open pattern plus one
close bar and open bracket one stop stop then close bar bracket then we are going to get a list
from 2 to 11 has class this way of that you can for example with numbers you can define a range
by starting with a starting while open bracket starting value stop stop full stop stop what
is that's called pista and ending bracket and ending value close bracket and this will produce
list of items from starting to ending if you omit the ending ending value you are going to get
an infinite list that works just fine you're not going to run out of memory until you try to
for example print that out on the screen or try to evaluate the whole thing
and for example if you add up if you want to do another another thing is that you can run
map or list for example open bracket one full stop stop then close bracket and you are going to
get a list of poollands that are going to tell if this value was odd or odd or not odd or even so
you're going to get a list of true false true false true false and so on
another pattern I talked about was taking a list and compressing that to a one value going
through the all the values and doing some calculation based on based on those and reducing
it to a single value and for Haskell there's a many functions for that of course and all of them
are fold something so there's a fold are fold L fold L prime and so on they all the basic idea
of all of them is the same but there's a little bit of differences how exactly they are doing
those things and the choice between them depends on how big the list you have and what kind of
characteristics of the processing you have the I'm going to include a link that talks about
interquities of the faults not not going to go through them here because I'm not
that good explaining them I barely know that difference between them but these faults they take
a function initial value and a list and then it produces then it reduces the list into a single
value so it does that by applying the function to the initial value and the first first element of the
list and then it will take that result and apply the function again to that value and the next item
of the list and it will continue at this until the list is empty and you have you are left with
a single value so for example fold R is a it takes a function from A to B to B so it's a
function of two elements A and B that produces a B it takes a B that's the initial value and it
takes a list of A and it produces a B it's starting to be a bit long type signature and again A, D
can be anything if we were called to fold R open pattern plus close pattern 0 open bracket one
stop stop 10 close close bracket we are going to get a value of 55 because we are
summing we are calling this plus function starting with the 1 plus 0 plus 1 and then plus 2 plus 3
plus 4 until we have summed all of them together this is so common pattern that there is a function called
sum that will if he gives sum open bracket one stop stop 10 close bracket we are going to get the
55 stack it's that it does the same essentially the same thing and then the another fold is fold L
you can think that there's a fold R as a fold right and fold L as a fold left
and fold L takes a it works in the same way similar way that it takes a but here the function is
from B to A to B and then initial value B and list of A and result is a B A and B can be anything
so fold fold L open pattern plus close pattern open a 0 open bracket one stop stop 10 close
bracket produces a 55 same result but here here if you if you compare the signatures the function
fold L is from A to B to B and fold L is from B to A to B so they are doing doing the application
and a little bit different well they are doing it and opposite opposite order in the plus it doesn't
matter because let me refresh in plus with small list it doesn't matter which one you use
because plus takes two values of the same time so A and B is the same value in case of plus
but if you have a list of say for example if you have a list of invoices and you are calculating a
total of the invoices then A can be a A is a invoice and B is a
money that's a pipe and here here there you have to think how you are going to construct what
kind of function you are going to give it and are you going to use the fold error or fold L because
that I that has to match you cannot sum invoice and money you have to take the money part of the
invoice and sum it the previous money to get the new money okay so I'm going to include the
link to the show notes that talk more about the folds so that you you if you are interested you
can go through them in time and the explanation there is much better than what I could be put
to here if you are interested on the intermediate values because folds probably only end result there's
a scan that's similar to the fold there's many scans and they return the instead of returning
only the end result the result intermediate intermediate results for example scan error is a
takes a function from A to B to B initial value to B list of A and produces a list of B so if you
compare that to the fold R it's almost identical but instead of producing a B it produces a list of B
so let's try this out if we have to call scan R open parent plus close parent 0 open bracket 1
stop stop 10 close bracket we are going to get a list with which is 55 54 52 49 45 40 34 27 19 10
and 0 so you can see that the 55 is the end result it's the same result that the fold R produces
and the next one is look it looks the same as the 55 minus one and then is 54
and the next one is 54 minus 2 which is 49 and then is 49 minus 4 I think I skipped one
one but in any case you can you can see that the right end of the list is the initial value 0
and then there's a 10 which is the last element of the list that we gave to it and then
there's the next element is one before the last element 9 plus 10 19 so it the list here looks
like that it is built from the right of the taking the right most value of the original list
and adding it to the initial list and then taking the next to that and adding that so it's
it looks on the blackboard but here you can see how the fold R processes the process
that one if if if you look scan L then that looks like a fold L so it's a function that it takes
a parameter function from B to A to B initial value B list of A and produces list of B
and if you use scan L open-turn plus close-parent 0 open-track at 1 stop stop 10 close-track
so we are using scan L to plus list of 1 to 10 we are going to get a result of 0 1 3 6 10 15
21 28 36 45 and 55 so this this looks much much more like what you would expect to happen
if you are summing all elements in in a list together and putting them the intermediate value
of the on to on to the list so which one to use again it depends on the case I I haven't
really used scan pretty much never at all haven't haven't had a need for that
the last last last type that we were talking about the last general pattern was that you you have
a list and you you want to take some values of that list and this got first so in for example
in in when I was learning programming in a basic I would have written a for loop that is from 0
to the length of the array and then checked each element in that that index and doing some check
and based on that result of the check would have added that to the another array and incremented
some count to tell me what where to put next element
but here you cannot you cannot do that easily so you can write that recursive definition that we
did earlier or you can use a general pattern called filter this is this is a function that takes
a function at a list and it will return a new list where each element satisfies that that check
and for example if we were called to filter out open bracket one stop stop then close bracket
we would be processing a list from 1 to 10 and this taking only the values that are odd
so and the result is at least one three five seven nine and if we wanted to know all the all the
even numbers in the world we can do that by calling filter even open bracket one stop stop close
bracket so we are omitting that and and and range so that will produce a list that starts with two
four six eight then twelve four things sixteen and it will go in in theory infinitely but at
some point you will run out of memory and it will it will crash your computer or crash the program
how to deal with this is that if you want to see for example five five first elements of that
list you can say take five dollar filter even open bracket one stop stop close bracket and that
will produce a list two four six eight then that take is a take is a function that takes that takes
two parameters first is the number of items to take and the second one is a list and that dollar
there is two is two there's a I don't know what it's called but in essence it means that first
evaluate the right side of this this definition and then put and use the value to the left side
you could replace that with a bracket not not brackets parents
so what writing takes five open parent filter even and so close close parent but I like I like
using the lot it it it's just there to instruct that the right side of this part should be evaluated
first and then to just that one you want the left side okay there's a those are the basic ways of
looping looping over a list and as I said the looping over a list and I'm sorry
looping from some number to another number and doing some operation it's basically basically
the same as looping over list of numbers there's even more tools I could actually go through
couple of them quickly I'm going to include link of some some some of them so in case you want to do
some a list construction you can use this and when you can construct lists then you can loop
over them and so no I'm not going I'm not going to give examples this time I just
brief overview of what's available these are in the prelude that is the basic basic library of
the Haska it has different contents of all kinds of interesting things so first one is iterate
this is a this takes a function from a to a and then takes a a and produces a list of a
and this is a funny function because it takes that initial value and it applies that
function from a to a into that and then it upload on the end result of that it puts into the
list and then it applies a to a again to that that value that you first produced put that into
the list and applies the function again to that so it's a it keeps it keeps calling that function
to those values that it's producing and producing more more values I don't know where to use
this that's just called my eye and look interesting this repeat takes a and produce a list of a
and this will produce an infinite list of one item I mean of one value so if you call repeat
with five you are going to get an infinite list of five replicate takes an int an a and produces
an list of a so this is a similar to repeat but it creates a finite list the first parameter
controls how long list to create and then there's a cycle that takes a list of a and produces a
list of a this will repeat will create an infinite list that repeats the initial list that you
so if you call it with one two three you're going to get an infinite list of one two three so one
two three one two three one two three are infinite and with those those you can create different
kinds of lists and then loop over them and do what you want to do there's even more tools of course
for specific situation and it's all about now now knowing or finding the right tools for the
situation and there's a luckily you don't have to remember then immediately you don't have to
read a big big a tick book and memorize that there's a tool called Google that is at the
HTTPS call on slash slash who will dot has call dot org and that's a half kill up the search engine
that's a really really useful tool I used it often all the time you can
use that to search out if you know name of the function but you don't remember where to find
that you can use who will define that tells you where it is in watch in what which package and
or if you have a general idea that you want to do something but you don't know how to do
that you can use to Google to search search that for example you know that that you want for
example if you if you if you wanted to for example you don't remember what repeat does or rather you
don't remember repeat as a name you could end there search into the Google ARO list of A
and it would find repeat for you so you can you can use that to search for the names that you know
that are there you can use it and that's not only limited to the function names you can search for
types also and you can also search for the type signatures so if you have a general idea what you
want to do and you know how to express it in terms of the type signature you can use Google
to help you find suitable function and I'm using that quite quite a bit quite a bit to find
when I when I suspect that this this sounds so common case that there might be a function for
this somewhere so instead of finding that by myself are you Google okay so that that I'm
hoping to ramp also time to prep it up so to recap Haskell is a functional language all the data
immutable you cannot you cannot change something as fast it has been assigned or said and that's
because Haskell is a non-strict meaning that the values are not evaluated or rather that values
are evaluated at the last pretty much last possible point and when you when you need a value
you are going to evaluate it and not sooner so you cannot if if if a value could change
this would lead into all kinds of problems but in Haskell because all the data is immutable you
can defer the evaluation to the last possible point you if you are really thinking about what
happening under under the hood in Haskell program you don't necessarily even know in what order
your program execute because in Haskell that does not matter time does not matter if you have a
function that depends on only on the values that are on your computer the time or inside of your
program that I am does not matter at all as long as the things are evaluated when they are needed
that's okay you don't need to know in what order they are evaluated but when you start talking
about talking about interactions for example writing to the disk or talking over the network or
reading the user input then then of course or printing to the screen then of course the time
matters overly low but that's a that's a topic for some other another time so Haskell immutable
data regular for looks don't exist but you can you can you have other tools at your
disposal the most commons are not fault and filter and there's other tools that you can find with a
Google okay that's all that's right
you've been listening to Hacker Public Radio at Hacker 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 hbr listener like yourself if you ever thought of recording a
podcast then click on our contributing to find out how easy it really is Hacker Public Radio was
founded by the digital dog pound and the infonomicon computer club and it's part of the binary revolution
at binwreff.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 commons attribution share a like three dot org license