liveBook · Manning

Type class

As explained in Functional Design and Architecture: Examples in Haskell

A type class is a language feature that defines a common interface of operations and permits implementations for different types.

A type class defines operations that a type must support. When a type has an instance of that class, client code can rely on those operations without exposing the type’s representation or selecting a concrete implementation directly. This makes a type class a functional way to express an interface and add shared behavior to user-defined types. section 4.3 section 1.3.3

Use a type class when code needs a capability rather than a particular data constructor. A `WithHandler handlerAPI` class, for example, supplies `withHandler`, which accepts a `DevicePart` and a callback requiring a handler. The caller requests the needed API through the callback instead of pattern matching through vendor-specific internals. section 4.2.5

This shifts responsibilities in a useful way:

  • Client code names the required handler API in its callback, such as `SensorAPI -> IO ()`, rather than extracting a handler from `DevicePart`. section 4.2.5
  • Instances decide how a supported `DevicePart` yields a `SensorAPI` or `ControllerAPI` handler. section 4.2.5
  • The public service interface remains the normal boundary; bypassing it to inspect internal constructors is a design flaw. section 4.2.5 section 4.3

Selecting a database at the type level

A database class can associate a phantom type with a database name. Distinct empty types such as `ValuesDB` and `AstroDB` receive separate `DB` instances. The key–value language carries `db` in `KVDBL db`, so a call can identify its intended database through a type application like `load "key1" @ValuesDB` or through an explicit result type. The database connection remains a separate `DBHandle db` dependency. section 11.1.2 section 11.1.2

Type classes can also select service implementations. A final tagless/mtl interface constrains business logic with `AstroService api`; type selectors choose HTTP or TCP instances at composition time. This can look like dependency injection, but carrying channel details and sharing an environment between business logic and instances can leave the layers tightly coupled. Type classes are therefore an option to assess against algebraic-data-type interpreters and free-monad interfaces, not an automatic architectural improvement. section 13.2.6 section 1.3.3

For broader type-level design, type classes provide limited expressiveness. Functional dependencies, associated types, type families, existential types, and generalized ADTs extend the available tools; dependent types are identified as a more powerful direction. section 11.2.2 section 11.3

-- module Andromeda.Hardware.Impl.Device.Types:
 
instance WithHandler SensorAPI where
 withHandler (DevicePart (VendoredSensor _ h)) f = f h
 withHandler _ _ = error "Invalid part API handler"
 
instance WithHandler ControllerAPI where
 withHandler (DevicePart (VendoredController _ h)) f = f h
 withHandler _ _ = error "Invalid part API handler"

Compare the two `WithHandler` instances to see how the same interface exposes different handler APIs while keeping constructor matching inside the instance. section 4.2.5

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Explains classes and instances through handler and database code, then notes advanced extensions and expressiveness limits.
Examples
Uses sensor and controller handlers, named databases, and HTTP-versus-TCP reporting services.
What it assumes
Assumes familiarity with statically typed functional programming while introducing type classes through concrete interfaces.
What you can do after
Apply type classes to require capabilities and select implementations without exposing concrete representations.
How it connects
Connects functional interfaces with Service Handle, dependency injection, phantom types, free monads, and final tagless/mtl.

Also explained in

Compare how 3 books explain type class →

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.