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

427 lines
30 KiB
Plaintext

Episode: 2818
Title: HPR2818: Writing Web Game in Haskell - Science, part 1
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr2818/hpr2818.mp3
Transcribed: 2025-10-19 17:17:19
---
This is HBR episode 2008-18 entitled, Writing Web Game in Hakell, Science, Part 1, and
in part of the series, Hakell.
It is hosted by Tuku Toroto and in about 43 minutes long, and Karima Clean Flag.
The summary is, Tukoto explains Types, and beta uses to model science in the Hakell
game.
This episode of HBR is brought to you by an honest host.com.
At 15% discount on all shared hosting with the offer code HBR15, that's HBR15.
Better web hosting that's honest and fair, at An honest host.com.
Hello, you are listening to Hacker Puppet Radio, and this is Tuku Toroto.
Today, I'm going to about the aspect in my game called Science, and this is a pretty
big topic, so I'm going to split it in two, so that this won't be too long episode.
Insert it in three, two short ones, hopefully.
So pretty much every 4x game has a research and big demo history, and mine isn't any
different.
So, the first part, I'm going to talk about how to model the research, what kind of data
base, what are the relations between things, and on the next time, I'm going to talk how
the research actually works, how things change over time.
So, this system is pretty much copied from the Stellaris and Victoria too.
Stellaris is another 4x game by Paradox, it's set in space, and Victoria too, I don't
actually remember who made that, I'll find it out, I'll put it in the show notes, and
that's set into the Victorian era, it's not a space game, but both of them has an aspect
of research, and I want to add some of my own flavor later on, but this was already
thinking of to write, so, once the first time.
The basic idea is that there's a three types of technology, and three types of research.
There's engineering, there's natural sciences, and then there's social sciences, and that's
pretty coarse division between fields, but three thousand five ideas.
Not too complex, not too simple, and each of those categories are divided into subcategories,
like in the engineering, there might be a material science, and in the natural sciences, there
might be a biology, and in the social sciences, there's a state craft, and then there's the
technology tree, but it's not shown to the players, they are.
When I have been playing those out-of-forks games, I have had some sort of analysis,
analysis, then I'm present with a huge large tree, and then I try to figure out what I want
to do first, so that I can get to the point that I want to be.
So here, we are not showing the three photo players, they essentially, they can have one
of each type of research going at any given time, so they can have one engineering, one natural
science, and one social science project going on, and they are given three random ones to choose
from, like when they start playing, they are given three random engineering researches,
three random natural sciences researches, and three random social sciences researches that
they have to pick from, and when they complete the research, then they are presented three
ones, and there are some technologies, lay them on, planned, implemented, that they can
raise this limit, so when they unlock certain things instead of three, they are presented
four options to choose from. There is three behind-of-everything, like there's researches
or projects that don't require anything, and then there are another projects that
regard that you have completed something before you can start researching those.
They are more advanced, they build on top of their old ones, but it's not shown
to the player, they are just a small set of projects that they currently cool
research, if they had access to them three random ones that they choose from, and every
research has a cost line, and in points, research points, and those research points are produced
by the buildings, and the different kinds of buildings, and they of course produce different
research points. There could be a nature institute, there could be engineering school,
there could be a deep sea, an exploration base, there could be a form from Aanum, things
like this. They all produce research points that are available for the player to allocate
to their researches they want to do. And I can say that when the research is completed,
it all inlocks things, if you research, for example, caravels, then you get access
to the caravels, lots of spaces, and then you can start researching some more,
more advanced food type, or something complete research. Okay, so let's do that
implementation. There's a data trace beyond of all this, like always, and there's a three
tables. Exact definitions are in the show notes, but give this that there's a
current research, that tells what's currently being researched, that has a three
fields, it has a type as a technology, progress as int, and function ID as a
function ID. And then technology tells what is being researched, progress tells how
much points have been accumulated to that project, and function ID tells which
function is doing this research. Available research is a another table that has a
distilled what researches are currently available to the player, the truth from,
and it has three fields, type as a technology, category as top research category,
and function ID as a function ID. The type tells again which technology could be
researched, category tells which top research category this research belongs to.
This is not, I could have derived or used a function to get that top
research category from the technology, but I wanted to place it in the database,
so it's easy to manipulate the data. You'll see, you'll see later on why it's
that, but that that that essentially tells if it's an engineering natural sciences
or social sciences project. And function ID again lets which function has access
please. And last table is complete research, distilled what research has been
completed, this is what the code queries and it wants to see if some
function has access to some, now something for example building or a specific
spaceship or whatever researches have unlocked. But here we have a type as a
technology, level as an ID, function ID, and data as an ID.
So again, type tells which technology it is, if it is it has some specific
hall is it that the farming equipment is it a universal basic income for your
planet, think like this. Level as an integral switch level you have.
I'm going to model things like you can unlock something, but you have very
low level of that something. For example, if you go out how to build
caravels for example, or dogs, you have a photo touch of a spaceship,
you have first you have access to very limited version of that one and when you
do a little bit more research, you get a better better version of that
specific available for you for building like you. Your scientists have
scientists and engineers and one not figure out that hey we can improve this
if you do something and then you have better access, now access to better
version of it. So it's not enough to unlock something but you have to,
well you don't have to work that it sometimes makes sense, well you do some
extra research to sort of level it up. First you get a very
experimental technology prototype and then later on you get more
much more technology. So that's that's in the level that as in.
And again, section ID is the section ID who it's the ID of the
fraction that has this technology available to them and date tells
the start date when this was unlocked.
But it's not as that pretty simple database in my opinion.
Three tables and only one relation to the fraction essentially there's no
relation between these three tables. Data types.
So again, these are shown in the show notes. It might be a good idea to
take a peek at them. I try to explain them as clearly as I can.
And here I'm showing something called deriving. I have been doing this
before but I haven't been talking about that as much.
Basically it means when you are defining your own data type,
you group write function that compares equality.
Like if you have, if you define a new data type,
you cannot compare equality. If you have two values of that,
you cannot compare equality. You're going to say if these are same or
not unless you implement ego instance.
You have to define a function that tells you that heart is equal.
And Haskell can do that for you. For some, in some cases,
there's some basic operations that you can,
that you could write by hand but you usually don't write your
instructor Haskell to do that for you.
That is the time with that deriving.
And what I usually do is I derives the show and read.
These are, show is for turning the data into string.
For example, different with your screen.
It's really helpful during the, when you're working on it with the code.
And read is for taking that string and turning that back to the data.
Eq is for the comparing equality.
These three are usually what I have pretty much everything that makes sense.
Eq not always but most of the time.
And then there's many, many other ones.
And I'm going to talk about this type of classes that you're deriving.
I'm going to talk about those in the same another episode.
More details, but now it's enough to understand that if you have an eq instance,
it means that you can compare your daylight if it's the same or some not.
And if you have org instance, it means that you can compare the
originality, which one is bigger than?
We ordered the same size.
Okay, so first one, technology.
This is an organization of all possible technologies.
It's a data type.
I mean, this is an organization of all possible technologies.
And I know it will be thick in the end, because at least I hope.
Because one thing I like about 4x games is that you have that big technology stack
free pile that you can explore and unlock things.
And then you find something really cool.
So this one will list all technologies that are there.
And only part of it is shown in the show notes.
And it is written as data, technology, eagles.
High sensitivity, sensitivity sensors, pipe side signals sensors,
pipe height and side materials, pipe satellite technology,
pipe wally house, pipe sauna house, pipe gravel house, and so on.
And in the end, there is a deriving open parents show,
comah read, comah igu, comah enum, comah pound, comah horde,
close parents.
So now if we have a value of technology,
something is technology.
Then it can have a, it can be one of these.
It can be wally house, or it can be side signals sensors.
Or something else for that list.
Then there's the research category that I mentioned.
This is tells if it is the research belongs.
What category belongs?
So this is data.
The research category equals n, pipe natska, not ski, pipe sok ski.
And then the deriving class in the end.
If you have a, the research category somewhere,
it can be one of these three values.
Basically, engineering, natural sciences or social sciences.
I solved them a bit.
I don't know if that was a good idea, but I live with that for now
and maybe change it later.
The thing I like about Haskell is that comah is really good telling you
when you made a mistake.
I, in the end, want to change those names to something else.
It will, the compiler will help me to fix the code.
It won't help me to fix the database though.
So it was in the database.
The research category is taught as a text.
So if I change m to engineering, the code will work.
But the data, data in the database will be incorrect.
And it will throw a random error for me.
So at that point, I would have to, if I were to make that change,
I would have to go and check the database and flip all the n-text
to engineering text.
That is a pain.
A research category, next data.
This is more refined to the division of the fields.
So, for example, the engineering has industry materials,
propels, and field manipulation, and subfields.
And, yeah, I should just say that data, research category,
equals engineering, engineering subfield, pipe, lateral science,
lateral science of field, pipe, social science, social science of field,
and the terrain clause.
And here, research category can have three values.
It can be engineering, lateral science, or social science.
And each of these values is parametrized by another pipe.
So if you have an engineering, it is parametrized by the engineering subfield.
So essentially, when I have an engineering,
when I have a research category somewhere, I know that it can be one of those three.
And I know that each of them can have some additional information.
But I want accidentally mixed subfields of the engineering and social science with each other.
And then that, for example, the engineering subfield would be data,
engineering subfield equals engineering subfield.
Ah, sorry.
That would be data, engineering subfield equals industry, pipe, materials, pipe,
propulsion, pipe, field manipulation.
And that tells what I can put into the engineering subfield.
Next is a research score.
This tells what is the size of some research.
And this is defined as a new night.
And that means that it is essentially like a in this case like a int number.
And during the compilation time, the research score actually will be converted to the int.
It will disappear from the code.
Only to help the programmer to keep this int separate from some other int.
So the idea is here that I, because I'm using, I need to keep track of research score.
I don't want to mix it with something else, accidentally.
I define a new data path for it called research score.
That helps the compiler to tell me if I'm about to mix things up.
But during the compilation, it will be converted back to the int after the program has been objected.
So they won't be any any performance problem with this.
But it is not that the performance impact will be big anyway.
But sometimes it might not.
And this is defined as a new type, research score A equals research score,
curly bracket, and research score, colon, colon, int,
curly, curly, curly bracket, deriving, open, so, comma, read, comma, eq, comma,
or, comma, nm, close burn.
And here I have the ord and nm data, nm.
Ord means that, and actually that I talk about that,
to regard that's ordinality I can compare.
If I have two research scores, I can compare which one of them is bigger,
or the other of the same size.
And nm, add some numeric operations.
I can add subtract multiply.
I can check the, I can take the absolute value.
I can check for the sign.
And I can, and I can call, learn, a number into research score.
And this is a quantum type.
There's a, on the left side, on the type constructor, the new type research score A.
That A is a type parameter.
But that type parameter doesn't appear on the right side.
If I create a, create a value of a research score, it will be,
it will be a, it, the A will be something.
And, but it, I don't have to specify that when I'm creating it.
Because the compiler will infer that from the, from the context.
Actually, I cannot, I cannot specify what it is.
The compiler will infer that from the context.
And, I had, had latest from the type signature of the function,
where it is being used.
And, from, from that point on, that research score value will have that A type parameter,
associated it, it, it, and it will, it, track of it.
And, that type parameter can differ in between different types of research,
scores, for example, if it's a, if it's a cost of something,
I can say that this is a research score.
And, engineering cost, for example, as a, right parameter for it.
Or, I can say that this is a, a research left.
Then, then this research score tells how much data, research left to be performed.
So, not only I have a research score type that tells,
that makes sure that I don't mix this int to some, some, some, another int.
But, I also can have different types of research scores,
so that I don't mix them accidentally with each other.
And, then there's the, this is a, one, one int.
Basically, then there's a total research score.
So, if you remember, there's three types of research,
there's the engineering, there's the natural sciences,
and then there's the social sciences.
And, that, that total research score groups all this together.
So, that is a data, total research score,
A equals total research score.
Open curly bracket, total research score, engineering,
I had a third 3d research score and engineering cost.
Hello, come on.
Total research score, naturally we have a third 3d research score,
natural science cost for my total research score,
social mental, third 3d research score, social science cost.
Whilst curly bracket Deriving open tabans
soul, Roma, Ried, Roma e.c. Clostin.
So, total reject score is a type or that is a record that has three fields.
Total reject score, engineering, total reject score, natural and total reject score, social.
And each of these are reject score, but they are using that phantom type that I explained,
I don't think that was a part of a record explanation, but using that one I am assigning
tends that this is an engineering course, this another one is a natural science course,
and this third one is a social science course, so I don't accidentally mix them with each other.
And then there's a bunch of singleton values, these are types that can have only a single value.
At the beginning I was thinking what's the point of having a type that can have only a single value,
if you have a variable of that type, it can only have single value, so what's the point?
But the point is that I can use that pipe in the phantom times, for example,
telling that this total reject score is some specific type of total reject score,
or another reject score is some specific type of reject score.
And that's the reason I'm using these singleton pipes here.
So there's an engineering course, which is just, well, these are, because these are singleton types,
I don't bother rattling out the definitions, I'm just telling what the types are, and the value is named,
it's the same. So there's the engineering course, there's a natural science course,
and so-so science course. These tell the different, different reject scores, different types of
reject scores above. Then there's a research course,
I have a filter project, yeah, yeah, then there's the research course, not to be confused with the
research score, like I just did when I was wondering what I had taught here. So there's a research
course that tells that the total reject score is about cost. Then there's the research production,
that tells that some, the TV I'm using, it tells that some total reject score is about production.
And then there's the research left, that tells that some total reject score is about how much
of research there's left is something, there's a presumable some project.
Okay, research, now we are getting to the thing that all this was built because of this,
basically. So research is a type that tells details of a research. It tells what technology,
it unlocks, it tells what you have to research before you can start research. This technology,
it tells what's the cost of doing, how much of research you have to do to unlock this,
there's a fire that I'm not using it, using it yet, but that will be used in the point where
player is given those random technologies to choose from. I'm going to, the higher,
higher here is quantifying how advanced the technology is. So I'm thinking that I'm going to
weigh in, weigh, weigh the randomness to favor lower technologies. So if you have a,
for example, if you have a five random technologies, three of those will be lower ones and two
ones will be higher ones. On other words, you might end up in the situation where you have five
lower than low, low than researches, or you might end up in the situation where you have four high
ones and one low than one, but that's what the fire is going to be used.
So, definition of the research, it's a generic word, it's a data research,
equals research, open curly bracket, research name, colon colon text, comma,
research type, colon colon, technology, comma, research category, colon colon, research category,
quenacoma, research antecedents, colon colon, open bracket, technology close bracket.
So, research antecedents is a list of technology, colon, research cost,
colon, colon, total research score, research cost, colon, comma, research type, colon,
colon, research type, colon, curly bracket, deriving, open brand, soul colon, soul,
coma, reed, coma, eq, close brand. So it's a several, several fields, name of the
research, has a text, there's the type of the research, that's the technology,
there's a category, research category, that tells if it's a what kind of engineering or social
science or natural science research, this is, there's the research antecedents that is a list
of technologies that you have to have unlocked before you can add into researching this one,
there's the research cost, that is a cost of this research, there's a total research
for engineering, natural and social, in depth. And then there's the research tires that is just
I think I didn't talk about the definition, but that's basically the same, similar definition as
the research score, so it's a new type for int.
Yeah, yeah, I actually, I have a bit of dilemma because the research cost is a total research
meaning that there's a three values, but then it can have three, those three values at any
given time. So it is possible that to define a research that has cost in the social sciences,
engineering sciences and natural sciences at the same time, and then in which the research
category that would belong, maybe to the one that costs most, so I have been thinking that if I
should actually change the total research score from the record to be a type that it can have,
it still can have a social sciences, natural sciences and engineering cost, but it can have only one
of those at any given time, because the system is heavily leaning towards the direction, it's on
my list of things to wander up out, but I haven't reached any conclusion there yet. But anyway,
that's a, that's how you define research currently. And we need a trajectory, so this is the three
that holds all possible research that can be done, and it's actually a list. I wanted to name
a trajectory, but then I ended up redefining it as a list, because this is much nicer to work with
the three, I think. And finding a research based on technology is a common operation, so I
defined a mapping for that, so it's actually a, the trajectory is just a list, so it's a list of
research, and then there's the deck map, that is a map of technology and research, so it's a,
I think in some, some languages these are called associative arrays, in some languages these
are called dictionaries, and here they are called maps. This is a bit confusing because then there's
that function, and then there's that data life, and they have very little to do with each other,
with each other. Okay, so the deck map is defined as a, it's a, it's type, type signature is deck
map, colon colon, map, stop, map, dot map, technology research, so it's defined in a module called
map, and it's type, it's map, that's why it's map, map dot map, and it takes two, at a type,
takes two parameters, it's, it's parameterized by two variables, first is the technology,
that means that we are using technology as a key, and the research is the value, meaning that when
we are, when we have a technology we can quickly look from that deck map if there's a corresponding
research, and that's done with a, a function called lookup, that takes a, that takes,
deck, tapes, I've left, no, it's my words, that takes a, well, the lookup type signature is a lookup,
colon, colon, ordk, fat arrow, k, arrow, not k, a, arrow, maybe a, meaning that k has to have
an instance of ord, that they have to be ordered, you have to be able to tell which one is
bigger than which one, which one, this is because internally the map is represented as a minor
tree, and you need to order to build the, build the tree for, quick lookups.
So k is something that has an orc instance, the function takes a k, which is the key,
then it takes the, that, the data structure of that has a k, as a, key, and a, as a value,
and it produces maybe a, so if you find, if, if the key is present in the tree, you get the,
value associated with the key, you get just a, and if it's not present, you get nothing,
so it's our, our friend maybe once again here, and uh, yeah, so that is used, that lookup can be
now used for the retrieving the value from the, our deck map, but I didn't want to define the
deck map in a way that I would manually build the tree, I mean the panel tree, so I used a
helper function from this, which is really nice, because here I can give a, uh, function,
the, from list takes a function that returns a, a, double, where the first value is the key,
and second one, second value is the, value that is associated, that will be associated with that
key, and list, and it will, based on those information, it will build you the panel tree,
so deck map equals map dot from list, dollar, uh, open parent slash x, arrow, open parent,
research type x, comma x, close parent, close parent, so this is our lambda function,
when we are given x, it will return a type, uh, sorry, it will return a double, where the first
element is research type x, so we are calling research type function on the x, and the
next, the second element is the x, so, present, presentable, we are handing over here research,
of record, and the x will be the research type, I mean some, sorry, for the x, if x is research,
then the research type of x will be a technology, and the x will be research, of course, so,
we are getting a, double tag, where the key is a technology, and first element is the
technology, and last element is the research, and then we continue the definition, uh, dollar diamond,
and dectery, dectery, because dectery is a new type, and from list doesn't understand that
new type, we have to take the new type apart and present the regular list to the, from list,
so this, this, this will take our dectery list, unwrap, unwrap it from the new type,
and for each element, it will create a double, where the first one is the research type,
x, which is a technology, and the second element is the research, and from those, it will,
it will build us a dectery, I'm sorry, a dectmap, which is actually binary, and from there,
we can use the lookup function to quickly find items, based on the technology.
I could have defined this in other way too, but first define the dectmap and from there,
then it will be the list, but I ended up creating the list first, and then realizing that this
is a series, or let's build a dectmap too, for, for, for easier, for easier use, might be that,
I might even get rid of that list completely, I'm not, I think I'm not currently using that,
that's, that's the thing, the thing about, writing programs, no matter how great,
plans you have, and plan, great ideas, at least for me, I always end up calling a
template, I hate this, was not the greatest idea, and then I'll leave a little to-do mark in the
code, and spent, we go to, going over, over that, thinking about it, and then at, at some point,
I either removed the to-do, or I reworked the code completely, from that point.
So, that's about the, how the data, and data types, and database are defined for the, for the
research, so there's a relatively many things going on, in the end it's not that many things, but
there's a still, it certainly self-quadlot, when I was writing this, and the thing is that there's a,
those three data, database tables, that tell us what is, what is currently being researched,
what can be good to your research, and what has been completed, and then there's the,
technology 3, that is presented as a list, and then there's a quick access to that, we are all
not, where you can search from with the technology, and the, part of those contains,
a group of researches, I mean research, type objects, records, that have a bunch of information
telling them, what kind of research this is, what, what does it unlock, and what has to be,
how much it costs to unlock this, and what has to be done, or research, before you can start
researching this one, that's the gift of it, next time I'll hopefully go into, go into,
how the whole thing actually works, how, how, where do we fill in the data into the available
research, and how that, how that may move from there to the current research, and from current
research to the complete research, and what does this mean, in the, for the, for example,
space in the building, okay, the best way to reach me currently, now this is either email,
that's the, in the, my, what, what is called correspond page, in the Hacker Public Radio,
oh, I'm also relatively active at the service, I'm too tired, I'm not tired at all, so,
and if you have any questions, comments, ideas, whatever, I would love to hear from you,
even better if you record your own episode, about things, I'm, at the same time, I'm trying
to do another, another sort of ministry, where I talk about little bit, about programming in
Hacker, so that it, it would be easy to follow, follow, and I'm trying to explain here,
so thanks, thanks, thanks for, thank you for listening, hard after.
You've been listening to Hacker Public Radio at Hacker Public Radio.
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. Hacker Public Radio was founded by the Digital Dove 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 comments, attribution, share a light, 3.0 license.