Long type level lists

At Co–Star, we use the freer-simple package to organize our code and model out effects. This library uses type-level lists to represent computations that require multiple side effects. For example, a computation might have a type Eff '[Reader String, State Bool] Integer which means that it’s going to read from some common String parameter and modify some Bool state.

We’ve defined all sorts of new low-level effects, but I think that we’re just now crossing a threshold where it’s going to be helpful for us to start defining higher-level effects. For example, we have a Sql effect for connecting to our database and an Http effect for making web requests. We have a Planets effect that calculates positions of astronomical bodies. These effects are everywhere in our codebase, since we’ll lazily attempt to set up different aspects of our users’ profiles (and cache them for next time). Instead of thinking about computations that are using all of these different effects, it makes sense to start thinking about computations in terms of a higher-level User effect. This effect could expose an interface that promises a certain part of a user profile and will handle the lazy setup and caching behind the scenes.

The benefit of this is that it’s easier to reason about what functions are doing, and it’s also easier to test. Instead of setting up three different test environments, we can set up a single one.

hlint won’t yell if you have a long type list in a type alias. It’s only a smell if it’s in a type declaration.