first-class-families: First class type families

[ library, mit, other ] [ Propose Tags ]

First class type families, eval-style defunctionalization

See Fcf.

[Skip to Readme]


Note: This package has metadata revisions in the cabal description newer than included in the tarball. To unpack the package including the revisions, use 'cabal get'.

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Versions [RSS],,,,,,,,,,
Change log
Dependencies base (>=4.9 && <4.15) [details]
License MIT
Copyright 2018 Li-yao Xia
Author Li-yao Xia
Revised Revision 1 made by lyxia at 2020-04-18T19:34:27Z
Category Other
Home page
Source repo head: git clone
Uploaded by lyxia at 2020-03-08T15:27:46Z
Distributions Arch:, Debian:, LTSHaskell:, NixOS:, Stackage:
Reverse Dependencies 26 direct, 124 indirect [details]
Downloads 12576 total (80 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2020-03-08 [all 1 reports]

Readme for first-class-families-

[back to package description]

First-class type families Hackage Build Status

First-class type families are type-level functions that can be composed using higher-order functions.

The core of the idea is an extensible kind of "type-level expressions" and an open type family for evaluating such expressions.

type Exp (k :: Type) :: Type
type family Eval (e :: Exp k) :: k

This library provides that core foundation, and also exports basic first-class type families.


For example, consider this simple type family:

type family   FromMaybe (a :: k) (m :: Maybe k) :: k
type instance FromMaybe a 'Nothing  = a
type instance FromMaybe a ('Just b) = b

With first-class-families (fcfs), it translates to a data declaration and instances for a single Eval family:

import Fcf

data FromMaybe :: k -> Maybe k -> Exp k
type instance Eval (FromMaybe a 'Nothing)  = a
type instance Eval (FromMaybe a ('Just b)) = b

That way, the FromMaybe constructor can be partially applied, and passed to higher-order fcfs such as Map:

Eval (Map (FromMaybe 0) '[ 'Just 1, 'Nothing ])  =  '[ 1, 0 ] :: [Nat]

Essential language extensions:

    UndecidableInstances #-}


  • Fcf.Core: definition of Exp and Eval.
  • Fcf.Combinators: general combinators to compose first-class families.
  • Fcf.Data.*: first-class families on common data types.
  • Fcf.Class.*: overloaded first-class families.
  • Fcf.Utils: miscellaneous.

The top-level module Fcf is a prelude to get acquainted with the library. For regular use, import what you need from the specialized modules above, preferably with explicit import lists.

import Fcf                       -- Simple but fragile

import Fcf.Class.Functor (FMap)  -- Explicit and robust


Overloaded type families

Value-level functions can be overloaded using type classes. Type families---type-level functions---are open by design, so overloading is as easy as just declaring them with more general types.

data Map :: (a -> Exp b) -> f a -> Exp (f b)

-- Instances for f = []
type instance Eval (Map f '[]) = '[]
type instance Eval (Map f (x ': xs)) = Eval (f x) ': Eval (Map f xs)

-- Instances for f = Maybe
type instance Eval (Map f 'Nothing) = 'Nothing
type instance Eval (Map f ('Just x)) = 'Just (Eval (f x))

See also

Contributions are welcome. Feel free to open an issue or make a PR on Github!