I’m not using extensible records in this project (source code). Game is a big custom type handling the different states a game can be in:
type Game
= Intro
| Playing State
| Lost State LossReason
| Won State
Most of the data from an active game is part of a State record. This can be modified when in Playing state and is frozen in a Lost or Win state.
type alias State =
{ river : River
, twinPosition : Coordinate.World
, yDirection : YDirection
, scores : List Feet
}
A key insight I had was that I generally had two kinds of actions:
State -> Statewhich only changed the current playing state (e.g.moveTwinsDownstream)State -> Gamewhich transition from one game status to another in response to a playing state change (e.g.checkLoseCondition)
I created Game.map and Game.andThen helpers to compose these two types of actions. In retrospect, I probably shouldn’t have used those names ![]()
I wrote a discourse thread about learnings from this project.