MyNixOS website logo
Description

First-class typeclass instances.

Reify classes as data types to manipulate instances as values

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.

Related work

  • 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.

Metadata

Version

1.0.0.1

Platforms (76)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-windows
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-windows