Domain Driven Type Narrowing

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:

  1. State -> State which only changed the current playing state (e.g. moveTwinsDownstream)
  2. State -> Game which 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 :sweat_smile:

I wrote a discourse thread about learnings from this project.

1 Like