liveBook · Manning

Higher-kinded data pattern

As explained in Functional Design and Architecture: Examples in Haskell

A higher-kinded data type is a parameterized data type whose field types can be systematically transformed by a type constructor.

The higher-kinded data (HKD) pattern defines one parameterized ADT whose field types can vary systematically. Rather than duplicate nearly identical domain and persistence records, keep the shared shape in one template and choose field representations through type parameters or a type-level selector. section 12.1.2 section 12.1.3

Use it when records have the same fields but differ by context: a new value may lack a primary key, a persisted domain value may have an `Int` key, and a database value may require connector-specific types. The template preserves one record layout while aliases select each useful specialization. section 12.1.2 section 12.1.3

A practical design proceeds as follows:

  • Identify the stable record shape and the fields whose types vary between domain and database representations. section 12.1.3
  • Replace each varying field type with a parameter when only a few fields differ, such as a primary key. section 12.1.2
  • Introduce marker types and a type family when an entire set of field types must be selected together. section 12.1.3
  • Expose concrete type aliases for each selected representation, keeping callers focused on domain, SQLite, or Postgres values. section 12.1.3

One meteor shape, several representations

A plain `Meteor`, a `RawMeteor`, and a `MeteorMbPk` need the same size, mass, position, and timestamp fields but differ in the identifier. `Meteor' idType` makes only `meteorId` variable: use `()` before persistence, `Maybe MeteorID` when a key is optional, and `MeteorID` after creation. When every storage field differs, extend the template with parameters—or select them from a named type set—for `Meteor`, `SQLiteMeteor`, and `PgMeteor`. section 12.1.2 section 12.1.3

The pattern counters type multiplication: separately declaring domain, optional-key, SQLite, and Postgres records repeats the same structure and makes changes costly. It does not remove all complexity; compile-time type selection and connector APIs can make types harder to read, and backend-supported column types still constrain a schema. section 12.1.3 section 12.2.2

Figure 12.2 The HKD pattern for meteor data types

Compare the single meteor template with its domain and database specializations to see how one record shape supports multiple field-type sets. section 12.1.3

HKD is useful beyond a single primary key: it can underpin relational-model declarations and SQL connectors while reducing repeated ADTs. Balance that reuse against the coupling and type-level machinery introduced by a particular library integration. section 12.3 section 12.2.2

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Works from a single varying primary-key field through compile-time type-family selection for complete domain and database field sets.
Examples
Demonstrates meteor records specialized as raw, optional-key, domain, SQLite, and Postgres representations.
What it assumes
Assumes familiarity with ADTs and relational persistence while introducing HKD through duplicated-record problems.
What you can do after
Build it from scratch by parameterizing varying fields or selecting field types from a compile-time type family.
How it connects
Connects relational models, domain models, primary keys, ADTs, type families, SQL connectors, and beam.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Design and Architecture: Examples in Haskell. The section links point to the parts of the book it draws on.