first-class-instances: First-class typeclass instances

[ bsd3, language, library ] [ Propose Tags ] [ Report a vulnerability ]

Reify classes as data types to manipulate instances as values


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.1.0.0, 1.0.0.0, 1.0.0.1
Change log CHANGELOG.md
Dependencies base (>=4.13 && <5), containers (>=0.6.0.1 && <0.9), template-haskell (>=2.15 && <2.24), transformers (>=0.6 && <0.7) [details]
License BSD-3-Clause
Copyright 2019 Matej Nižník
Author Matej Nižník
Maintainer lysxia@gmail.com
Category Language
Source repo head: git clone https://gitlab.com/thematten/first-class-instances
Uploaded by lyxia at 2025-07-29T17:51:26Z
Distributions
Downloads 383 total (6 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2025-07-29 [all 1 reports]

Readme for first-class-instances-1.0.0.1

[back to package description]

First-class instances

GHC compiles type classes as data types. first-class-instaces makes that correspondence explicit with a simple but powerful mechanism to define instances. This enables implementations of deriving as libraries.

Overview

Type classes as data types

Type classes are associated to data types using the mkDict command.

Example:

class Monoid a where
  mempty :: a
  (<>) :: a -> a -> a

mkDict ''Monoid

That generates the following data type:

data DictMonoid a = Monoid
  { _mempty :: a
  , (|<>) :: a -> a -> a
  }

Dictionaries

The Dict type family maps constraints to their corresponding dictionary types.

type family Dict (c :: Constraint) :: Type    -- Defined in FCI

type instance Dict (Monoid a) = DictMonoid a  -- also from mkDict ''Monoid

A constraint c can be reflected as a dictionary:

dict @c :: c => Dict c

Instances from dictionaries

A dictionary d can be reified as an instance.

Example:

instanceDict [| d :: Dict (Monoid T) |]

That generates the following instance:

instance Monoid T where
  mempty = _mempty d
  (<>) = (|<>) d

Show me the types

The core API of first-class-instances:

{- module FCI -}

type Dict :: Constraint -> Type

dict :: forall c. c => Dict c

mkDict :: Name -> Q [Dec]

instanceDict :: Q Type -> Q [Dec]


{- module FCI.Unsafe -}

(==>) :: forall c r. Dict c -> (c => r) -> r

Deriving as a library

These simple primitives can be used to implement "deriving as a library". The adventure continues in ad-lib.

  • The reflection library is another approach to convert constraints into first-class values, and back. It provides a solution for implicit configuration, rather than deriving type class instances for user-defined types.

  • In Agda, all data types are type classes, exemplifying the orthogonality of declaring a data type, and passing values implicitly as instances. Haskell requires instances to be globally unique: there must not be two instances Monoid T for the same T.