Project Serpent: Day 4

Halfway through my first week, and it looks like unless things pick up I’m going to be taking a second. That’s fine though, just as long as I keep working.

Right now I have a very preliminary “step game” function that allows the snake to move around, maintaining its length, but doesn’t do any collision detection (including whether it has eaten any food). The obvious thing to do here would be to detect collisions and remove food (code is already in place to grow the snake if the collision detection signals that food has been eaten), but instead I’ve decided to take a little break to switch to working on the front end.

What have I been doing on the front end? Well, as in everything, there are degrees to this, and I’ve only been working on the “middle” front end so far — actual rendering and user input aren’t coming yet, but I’m one abstraction level closer to that. I am writing code that is “aware” that user input and frame rates exist and must be taken into account.

I’ve been handling this as follows. There are a few rough “parts” to the Effects library: the specification itself (defined in Spec.idr), the “resources” that are required to back those effects (which I define in GameState.idr), and “effectful programs” that make use of the operations defined in the specification to manipulate the resources. The great thing about effectful programs is that they can have a list of effects available, and can use operations from any of them. So for example, I’m writing programs right now with access to [GAME (Playing False rules), FPS 5]: I can manipulate a game that’s unpaused, and… hey, this FPS thing is new!

FPS is an effect I wrote yesterday night when I realized that if I’m writing code that will run on every browser frame, I shouldn’t necessarily have that code run a simulation tick every time. The coordinates I’m planning to use in Serpent are relatively low resolution, and moving forward by an entire “square” every frame would be way too much. So the FPS effect manages a little counter that can be queried to say “Hey, this much time has passed since I last talked to you. Should I run another simulation tick yet?”. Currently I have it set up to run 5 ticks per second, but that can be easily adjusted later.

Of course, 5 ticks per second is fine for the game clock, but a UI that runs at 5 FPS is going to be annoying. I plan to solve this using tagged effects: [FPS 5] represents the ability to respect a clock that runs at 5 ticks per second, but ['GameClock ::: FPS 5, 'UIClock ::: FPS 60] represents the ability to respect both a game clock that runs at 5 frames and a UI clock that runs at 60 frames per second. This is similar to how many RTS games run on a coarse-grained clock used for the simulation and a finer-grained clock so that nice animations can be shown between the game’s relatively abrupt state transitions.

And finally, right now I’m just writing a function from user inputs to effectful programs with access to [GAME (Playing False rules), 'GameClock ::: FPS 5, 'UIClock ::: FPS 60], but I plan to soon write an effect representing input as well. After that, I hope to be able to write code like this:

if !('GameClock :- tick delta)
  then turn !getDirectionCommand
  else pure False
if !('UIClock :- tick delta)
  then {- draw a new frame somehow -}
  else pure False

Of course, I’m not quite there yet. But I think I should be by the end of today!

Project Serpent: Day 3

Yesterday I spent some time improving my MenuInput data type. I realized I haven’t mentioned that at all in this series of posts, so I’ll talk about it a little.

A MenuInput basically describes an editable entry in an options menu. Simple menu inputs might be things like NatBox "Number of heads" 3. This represents an input box that can contain a natural number, labeled “Number of heads”, and whose default value is 3. Similarly, FloatBox "Game speed" 1 is a box called “Game speed” that contains a floating point number defaulting to 1. There are also selection boxes, like Options "Hair color" ["blue", "green", "red"] "green", which means that there are three choices for hair color defaulting to green. And finally, there are toggle options with additional configuration available if they’re toggled “on”: Toggle "Gravity" [FloatBox "Strength" 9.8, Options "Direction" ["up", "down", "left", "right"] "down"] means that gravity can be either on or off, and if it’s on you can also configure its strength and select one of the four cardinal directions for it.

Every kind of menu input has a type of values that it accepts. A NatBox accepts natural numbers, a FloatBox accepts floating point numbers, an Option accepts one of the available strings from the list of choices1, and a Toggle can either be “off” or it can be “on” with a list of values for the extra configuration options. Because Idris is a dependently typed language, we can actually encode this statement as a function from MenuInputs to Types, and that’s exactly what valueFor does in Spec.idr.

So part of my time yesterday was spent writing additional utilities for working with lists of menu inputs and the values they can take. For example, I have a function to apply an update2 to a particular entry in a menu, or to get the value of a certain entry.

Anyway, that is one system I have developed that I hope to get a lot of use out of when I get to programming the menus. So far, I’m not there yet, but I’m getting there: the other thing I spent time on yesterday was my skeleton implementation of the game state, with a focus on states in the “in-game” phase. Right now I’m working on what you might call the meat of the game: stepping a game state by moving the snake, doing collision detection, and possibly growing it or ending the game.

Today I’ll finish writing functions for stepping the game state, and hopefully by tomorrow I’ll be ready to start hooking those functions up to some kind of UI!


  1. we represent these in Idris as strings paired with proofs that they’re in the list of available options. 
  2. I also have a function mapping MenuInputs to the kinds of updates you can perform on them: for example, a Toggle can be toggled and a NatBox can be incremented or decremented, and any input can be set to an exact value. See updateFor in Spec.idr for details. 

Project Serpent: Day 2

Yesterday I only barely got my four hours in — a reminder, I suppose, that even in the wake of my accomplishment, finishing larger projects will still be difficult for me. I’ll have to be more careful about starting to work a bit earlier in the day.

Once I did get started working, I think I got a reasonable amount done. I started by defining a type for the concrete game state (parameterized by the “phase” category I talked about yesterday), which should store everything that’s necessary to represent and evolve the game. After that I wrote a skeleton implementation of a handler for every command I defined in Spec.idr. But while working on this, I realized that my types were looser than they needed to be.

I took a break to think about this and ended up storing in all Phases the set of active mutators and their parameters. For now, this mostly lets me specify the menus more tightly: the Reset command, for example, now states in the type that it resets all mutators to their default states, and the SaveMenu command states that it does some validation checking and then either stays at the menu without changing anything or returns to the main menu with the new parameters in effect. All the other commands also state that they don’t change the set of active mutators.

Making the mutator state available to this set of rules also opens the way for a much more dramatic change later: I’ll be able to add to the Playing phase parameters like the snake’s length and score, so that rules about how the snake grows can be encoded in types too!

Of course, with all this type fun, I’ve still done little work on the game’s implementation. I’ll have to pick up the pace soon.

What I Gained from Hacker School

I spent the last two and a half months at Hacker School, which has been described as a “writer’s retreat for programmers”. You fly out to New York to their space, where you join a bunch of other programmers, providing social pressure to do some programming every day and a community of people with whom you can talk about programming. For a solitary person such as myself, both of these are extremely helpful and novel.

Hacker School is also completely free to attend and even has cost of living grants for a steadily growing set of demographics. Their business model is like that of a recruiting agency: they help out any Hacker Schooler who is looking for a job and charge companies for hiring these people. For me, this sounded almost too good to be true: having never had a job, I was desperate for help breaking into the technology industry through the wall of college degree and years-of-experience requirements. But there was no way my parents could afford to fly me all the way out to New York and put me up in an apartment for two and a half months.

So I went to Hacker School for two reasons: to experience and environment where programming is a normal part of life, and to get a programming job. What did I actually get from Hacker School?

First and most exciting: I did get a job. The wonderful Hacker School facilitators, especially Sonali Sridhar, guided me through the process of writing a resume that is impressive despite its lack of experience, and of reaching out to Hacker School’s various partner companies. I got more interviews in a couple weeks than in the six months I had spent optimistically looking for a programming job on my own. And while most of these leads eventually turned me down, one company seemed consistently impressed by me and kept inviting me back… and on December 1st I start with Prismatic. When I got accepted to Hacker School I hardly dared hope for an outcome this good, and it definitely wouldn’t have happened if not for Hacker School.

There are also some things I gained that I hadn’t really anticipated.

For example: I have been wanting to start a blog for at least a year, probably longer, but never been able to commit to writing regular posts. There might even be a handful of dead WordPress or Blogspot blogs of mine scattered around the web — I don’t remember any of them, and certainly there are none with more than one post.

But at Hacker School I started to realize that people like hearing what I have to say. I even gave a little 20 minute talk and the handful of people who wanted to hear it seemed to enjoy it. And at the same time, I got together with some other Hacker Schoolers who were also trying to commit to writing one blog post a week. At first I thought this attempt would be like all the others, that I’d make a handful of posts and then forget again. But it’s been three months and I’m still posting… and people are even reading.

And I didn’t produce anything at Hacker School that I’d call finished, but that’s normal: I hadn’t really finished any projects before Hacker School either. What isn’t normal is that after Hacker School, I noticed this deficiency and corrected it. I can’t help but think that Hacker School’s atmosphere of programming every day had something to do with this sudden burst of productivity.

Finally, there’s something I feel like I could have gained from Hacker School that I didn’t. I met a lot of people there that I had fun interacting with, people who I would have been happy to get to know better and who probably would have been happy to know me… but I didn’t come away with any new close relationships, mainly because I have difficulty initiating and sustaining interactions. But even here it’s not too late: the Hacker School community is broad, and there are resources in place for helping alums connect with other alums and with current hacker schoolers. I hope to make a bit more effort along these lines as soon as I can work myself up to it!


Finally, did I mention that Hacker School is always looking for new applicants? If anything I’ve talked about sounds interesting, check out their site — it could cost you nothing at all!

Project Serpent: Day 1

My work today mainly involved planning out Serpent’s features in more detail. I decided on the screens that would be featured and, on the options screen, what gameplay parameters can be tweaked. In my Day 0 post I referred to these parameters as a “Bastion-style difficulty system”, but from now on I’ll be referring to them as mutators — ways to change the game. A rough outline of what I came up with is available at spec.txt in the git repository.

Once I’d decided on the game rules and the relationships that would exist between various screens of the game, I wrote a small description of them in Idris. (This doesn’t involve any implementation yet, just stating relationships and enumerating the actions available from each screen.) You can see the results of this in Spec.idr in the git repository (the relevant definitions are Phase and Serpent), but this part merits further explanation:

The standard way to do game programming (or anything else that you might think of as having a “main loop”) in a functional language is like this. You define a data type for storing the game state, and instead of a traditional main loop you have a function from game states to game states. (In Haskell-like languages, this might return an IO GameState instead, or it might be a pure function that also takes a representation of the user input state like I used in Pong.) And then you just recursively call this function forever, and that’s the equivalent of a game loop.

The method encouraged by chapter 6 of this Effects tutorial is a refinement of the standard one. Instead of having all game states be the same type, you introduce an additional layer of categorization: a game state that represents the player looking at the main menu might be a different type from one that represents a player in the middle of a game. The reason for this is to encode the notion that some actions only make sense in certain situations: you can only “turn left” if you’re in the middle of actually playing a game and haven’t paused. The Effects library lets us make these kinds of statements known to the compiler.

Here’s the categorization of game states I ended up using, and a brief explanation of my reasoning:

  • First, Playing, which represents actually being in a game. Playing states are further divided into paused and unpaused, which I represent as Playing True and Playing False respectively. In unpaused states, the player can pause or issue commands to the snake; in paused states, the options are unpausing, restarting, or quitting to the main menu. I thought of storing extra information in this category, such as the length of the snake and how many free spaces or pieces of food were on the board, but I decided against it for the moment because the way these things change is heavily influenced by mutators. I might factor these into the categorization if I find a neat way of doing so.
  • Next, the MainMenu. Here, the player can click one of a set number of buttons, such as “new game” or “change mutators”. Since I have a pretty good idea of what the buttons are going to be, this category doesn’t have any internal structure. All game states representing the main menu have the same type.
  • Subsidiary Menus (of which my current design calls for only one, the mutator menu, but there could conceivably also be a sound/graphics options menu) are further sub-categorized by the set of inputs available, where an “input” might be a named toggleable button or numerical slider. The available actions are then to update one of the inputs (the first half of Spec.idr is concerned with describing the different ways to do this) or to exit the menu with or without saving.
  • Finally, the GameOver screen. Like the MainMenu, game-over states are not further categorized: from any game over screen, the available actions are to restart or quit to the main menu.

None of this says anything about what information any kind of game state should contain, or how to apply one of the actions once the player has chosen one to reach another game state — so that’s what I’ll be doing tomorrow.

Project Serpent: Day 0

As phase two of teaching myself the skill of finishing things, I’m going to be working on a well-defined project for a week or two, spending at least a couple hours each day. I plan to begin this project tomorrow, which means I need to get ready today.

So here’s the project: I’m going to be writing a Snake clone (and I’ll call it Serpent, because why not?). By itself, this is probably another Pong-level task that I could do in 48 hours. There are two ways I’d like to make it a bit more interesting:

  • I want to use Idris’s Effects library to write a specification of the game’s rules as a type, which will then be checked by the compiler. I didn’t do this last time because I’d never used Effects before and I didn’t have time to learn it, but I really love the idea of the library and I think it could be a helpful tool for organizing programs!
  • I will incorporate what I like to refer to as a “Bastion-style difficulty system”, which might require some explanation. In the game Bastion, there is a “shrine” at which you can defy various in-game deities, incurring their wrath and making enemies a bit stronger. The effects of this can range from just making enemies hit faster and harder, to making them phase through attacks randomly, to making them explode on death. This is a lot more interesting than the usual “easy/medium/hard” difficulty slider that you find in a lot of games, so I’d like to try something similar.

I’m going to spend today going over some of the lessons I learned from my Pong jam and practice taking advantage of them — I’ll write a simple library for describing the callback structure I was using and try to learn a bit more HTML. Tomorrow, I’ll try to write up a specification and translate it into Idris!

The Skill of Finishing Things

In my last post I mentioned that one of the reasons I did my little game jam was social pressure: I felt my programming skills and ideology were under fire, and wished to renew my confidence in them.

But there’s another motivation behind the game jam, one that has been stewing at the edges of my mind for much longer. It’s about the Skill of Finishing Things.

One of my favorite things to do in my free time is to just play with ideas. I just sit around and mull over something in my mind: maybe a game idea, or a mathematical curiosity, or an imagined scenario of the future, or a conlang idea, or some fictional setting or conceit or sometimes even a plot. But (and this seems to be a very common problem) I have a hard time seeing these things through to completion. I realize that it’s okay not to turn every cool idea into a finished product; that would be impossible. But I really wish I could pick, say, one idea per month, or even every six months or every year, and stick with it (even if I consider other things in my free time) until I have something to show for it.

And my Pong jam was one small step in that direction. I had done game jams in the past, but never finished one before — I’ve always been too ambitious. I just desperately needed to have something to my name that I could call complete, so I set my sights as low as possible and gave myself a deadline short enough that I could stand to spend almost every waking hour working until it was done. And that worked, and now I have a shiny thing to show off that’s actually complete. Great!

But where does this leave me? I found a way to finish small, unambitious things. That’s better than nothing. Certainly it’s a hugely important symbolic step — the pride and confidence I felt when I finished were immense, and now if I ever want to develop any small ideas I know a way to do it. But setting a close deadline and spending every waking moment working is not a scalable approach. I can neither repeat this procedure to finish many small projects in rapid succession, nor can I extend the deadline to finish a larger project in this way — that’s just too much strain, especially since I’ll be starting work at an actual job soon. So I need to find another way.

I think the next step is to try to find a way to extend this “game jam” model to a slightly longer project: commit to dedicating at least a particular proportion of my time to the project, and set a deadline after which I’ll call the project finished. This will be inherently more difficult with a longer deadline, but sometimes there’s no way around difficulty — I’ll just have to develop the discipline to do it.

I think my next attempt will be “work four hours a day and finish in a week”. I’ll post again when I decide what to work on and when to begin.

Impromptu Pong Jam: Postmortem

Earlier, I decided that it would be cool to try to write a browser-based Pong in 48 hours. So I set the date for this past Monday and waited. Now it has been 48 hours, and… I’ve succeeded!

As is traditional, I’ll close with a postmortem. But first, a little story about why this victory means so much to me:

My experience at Hacker School was very enjoyable, but toward the end there was a single somewhat unpleasant event. On almost the last day, there was a “jobs dinner”, at which people from a bunch of different Hacker School-partnered companies came over to talk about where they work and meet Hacker Schoolers. At this point I was already pretty confident that I had a job, but I went anyway because it seemed a prudent thing to do. And because I was working on a type theory thing at the time, whenever someone asked me what I was working on I mentioned types.

Now, probably part of the blame for this falls on me, because I was bringing up all the theoretical stuff I’m interested in to a bunch of people with very practical jobs. So it would have been reasonable for them to not revise their estimates of my capability upward. Being enthusiastic about theory does not necessarily imply competence in practice. And maybe that was the extent of their response, just behaving reasonably and treating it as fun-to-hear but not really relevant, but… the impression I got was a bit more like

You work with types? That’s kind of cool I guess, but we’re productive here. That means we use real languages like Go and Javascript, which you probably can’t use and don’t want to learn.

And an evening of this elicited a pretty strong reaction from me. First of all, I felt insulted, as if these people were under the impression that I’m only allowed to be good at one thing, and if I picked types, well… have fun in your little ivory tower while we do all the real work! And faced with all these people in industry saying that a good type system just gets in the way of real work, I started to feel uncertain. I’ve always maintained that a good type system just helps you tell the compiler what you were already thinking, and that once you know the language moderately well it hardly gets in your way at all. But what if these people were right, and types were in some ways strictly inferior to dynamic languages?

This point kept turning over in my mind, occupying a couple days of thought. And soon it fused with some other insecurities I had been having about not having seen anything to completion at Hacker School. And so I set myself a challenge: two days, browser technologies I’d never used before, and at the end of it I must have something I’m proud to call a finished product. To prove that types aren’t a waste of time, that you can be productive with things that are not Go or Javascript, that I’m not a naive denizen of the Ivory Tower shrilly insisting that she knows the workings of the world.

And here I am, with a finished product written in Idris (a language with one of the most powerful theoretical type systems I know of) in 48 hours. My confidence is restored.

Anyway, enough soapboxing. Here is the actual postmortem.


Features

In terms of feature completeness, I had more than enough time to include almost everything I dared dream. Parameters like paddle size and the bouncing behavior of the ball are adjustable; I have a two-stage score card after every round that shows (by ticking their score up) who won; I have an AI that is actually kind of fun to play against and watch; there’s even an attract mode that pits two AIs against each other with randomized parameters. I think the only thing I even contemplated including that I didn’t get around to was sound.

Architecture

This was my first time ever writing code intended to run on the browser, but it’s already acquainted me with the concept known to a lot of javascript programmers as “callback hell”. Code that runs in the browser must regularly return control to the browser in order to work. In principle this would be a really nice textbook use case for building up infinite structures of “commands” with productive corecursion. In Javascript… you instead register “callbacks”, little pieces of code (that can’t communicate with each other) to be run when a certain condition is met (such as a given amount of time passing or the user clicking a button). If your application needs to be constantly running, in order to update a gamestate according to user input for example, you need to manually split up your loop into “productive” pieces that will run quickly and then return control to the browser, and then arrange for these callbacks to be triggered regularly.

This is actually a bit easier in vanilla javascript than for my purposes, because in vanilla javascript you can use state variables to circumvent the fact that callbacks can’t directly communicate with each other. There is a ready-made javascript function to register a particular callback to run regularly every few milliseconds, so you can write a callback that reads and writes some global variables and that’s your game loop.

I could have done this in Idris if I had wanted to, but I prefer a different approach to software design that makes minimal use of mutability or global variables. The way to imitate a game loop with mutable global state in a functional programming language is to have a function that recursively calls itself and store the “mutable” state as that function’s argument. But this doesn’t immediately lend itself to a callback-based approach: callbacks have no way of passing the updated state between each other.

After some worrying, frustrated hours of thought, I found a solution. At any given time, I’d have exactly one time-based callback waiting to resolve. This callback would reference a particular game state, simulate one frame and draw the results, and then register another time-based callback to do the same with the updated gamestate. This was frustratingly similar to standard recursion except that a lot of annoying boilerplate was involved. I think this could have been made a lot easier with a Continuation monad or a functional reactive programming system or an abstraction relating this infinite series of callbacks with a codata structure, or… something, but in 48 hours I had no time to find the elegant underlying pattern and crystallize it into a useful abstraction. Maybe some other time!

What should a Pong AI look like?

This is a question I struggled with for a while. It turns out it’s really simple to design an unbeatable AI player: just have it always, exactly follow the ball. In code-speak, always update the center of its paddle to have the same y-coordinate as the center of the ball. And indeed, this is what I did in the early stages of development, because I desperately needed to have the ball bouncing back at me and this unbeatable AI is perhaps the simplest Pong AI possible (other than “don’t move, ever”).

Once I had the basic architecture of the game loop ironed out, and had turned my attention to making the game fun to play, I had some questions to answer. How do I cripple this perfect AI but leave it competent enough that it’s still fun to play against and can beat a human on occasion?

I ended up deciding to give it a speed limit. This speed limit is actually not quite constant: there is a “maximum speed” which the AI reaches when its y coordinate is very far from the ball’s; the closer together they are, the slower the paddle follows the ball. The AI also gets extra lazy if the ball is far away in the horizontal direction. This gives it a nice feel where the AI paddle will kind of sedately move in the direction of the ball when it’s halfway across the table, followed by a quick repositioning when it gets closer. I’m sure there are better behaviors to give (maybe an AI that tries to return to the center of the table after hitting the ball, like a human ping pong player returning to bodily equilibrium), but all the same I really like what I came up with.

Attract mode: functional programming to the rescue!

For attract mode, I knew I’d want to have a pair of AIs playing against each other. Luckily, I already had the AI tracking logic factored out into a separate function, and this required only a minor adjustment to calculate the desired position of a paddle on the human side, so figuring out what the left paddle should do was pretty simple.

The issue was my step function, which advances a game state by one frame. Since you can’t advance the game state by a frame without knowing where the player’s paddle should be moving in that frame, that meant my step function had to reference player input, which meant I couldn’t reuse it for attract mode where the left paddle should be AI-controlled.

Oh, wait. I’m writing in a functional language, and step is a pure function from input objects to outcomes (an outcome is either “the next frame of the simulation”, or “the player won this round”, or “the AI won this round”, or “the player pressed Escape, so we should return to the main menu”). An input object is a simple bundle of data containing a mouse position and a boolean representing whether the player has pressed “escape” — the normal source of such objects is from an impure IO action that reads the player’s input, but there’s nothing saying that has to be the only source. So all I had to do was construct an input object stating that the player had moved the mouse to the position that the AI would have moved to, and we have a virtual player!

(For bonus points, I later realized that it would be nice to be able to press escape to quit from attract mode back to the main menu. This, too, was a simple adjustment — instead of constructing an input object from whole cloth, I procured one from the normal impure IO action and just updated its “mouse position” field, leaving the “escape” boolean faithful.)


In conclusion: I am super happy with the outcome of this project and you should totally humor me by playing for a few moments! (And watch attract mode, because I am so proud that I managed to make it work.)

If you’re interested in the source, here it is one more time: https://github.com/trillioneyes/idris-pong.

Let’s try a game jam!

I just finished a batch at Hacker School and I had a great time there. I spent a lot of time programming and learning math and other cool things, and I was surrounded by other programmers doing yet more cool things and happy to listen to me talk about what I was doing.

But there’s one thing I planned for Hacker School that I didn’t really do: I wanted to make some self-contained project that looks nice and finished. Finishing things is a separate skill from programming, and I don’t have it, and I really wish I had it because I have so many cool ideas that I wish I could birth into the world.

But it’s not too late! Hacker School’s motto is Never Graduate. Lately I have been working on implementing Go1 in Idris, since that seems like a fairly straightforward task with objective criteria for completion. And while I still think that is a good idea, I realized that I can probably do better in service of the goal “get something into a finished state, as quickly as possible”.

So. I am going to set myself a 48-hour one-woman2 game jam, from Monday the 17th to Tuesday the 18th. Forget Go during this short period; I’m going to write Pong and figure out how to get it running in a browser (Idris can compile to javascript, so I’m certain it can be done).

I am posting this here partly to have a record of when and what I’m planning to do, and partly for social accountability. Once the word is out, there can be no going back!


  1. the game, not the programming language 
  2. unless anyone would like to join me. That could be fun! 

Pluralities of Ideas

Let’s try a short post for once!

In the shower this morning I had an idea for a blog post. I imagined myself writing this blog post, and some interesting issues came up, and… suddenly I had ideas for two blog posts! I internally debated with myself for a moment before deciding that the second was more interesting, so I dropped the first line of thought and started imagining myself writing the second. Surprise! Another interesting thought, and now I’m trying to hold three blog posts in my head!1

This isn’t just about blog posts. Finding an idea (whether it’s an idea for a program/game/app of some kind, an interesting mathematical notion you’d like to explore more deeply, or just some kind of question) is a lot easier than carrying the idea through to its completion. It is not realistic to ever expect to have “caught up with your backlog” of cool ideas you’ve been wanting to follow up on.

We can look at this pessimistically or optimistically.

On the one hand… there’s this mountain of work growing in your brain, and you’re trying to pull off manageable pieces and get them done but deep down in your bones you know it’s growing too fast for you to keep up, and worse, this is the kind of deep-down-in-your-bones feeling that gets confirmed, not refuted, by rational thought.

On the other hand… maybe it’s not work, but new space to explore. Maybe you’re a mountain climber, and you’re exploring things as fast as you feel like, secure in the knowledge that you’ll never need to slow down to conserve the wilderness. You’ll never run out of new places to go. And this is the kind of security that gets confirmed, not refuted, by rational thought.

(Of course, even if you take the optimistic view, there’s sometimes the worry that you’re not a good explorer. But that is a subject for another day.)


  1. It is probably a good idea to write these down, so. 1) Some Haskell people think there are problems with trying to give a rigorous semantics to IO, and I want to flail around developing a mental model and maybe independently derive their objections. 2) Loosely, monoids are things that can be “smooshed together”, but slightly more rigorously they can be smooshed together in exactly two ways (ab versus ba). What structure might we get by imagining that we can smoosh things together in several ways, or even something like Legos? 3) “Accessible” terminology and some (surmountable?) problems thereof.