Tools for functor combinator-based program design

Version on this page:
LTS Haskell 21.25:
Stackage Nightly 2024-02-26:
Latest on Hackage:

See all snapshots functor-combinators appears in

BSD-3-Clause licensed by Justin Le
Maintained by [email protected]
This version can be pinned in stack with:functor-combinators-,5514


Introductory Blog Post / Hackage

Tools for working with functor combinators: types that take functors (or other indexed types) and returns a new functor that “enhances” or “mixes” them in some way.

The main functionality is exported in Data.Functor.Combinators, but more fine-grained functionality and extra combinators (some of them re-implementations for compatibility) are available in other modules as well.

The goal is to represent schemas, DSL’s, and computations (things like parsers, things to execute, things to consume or produce data) by assembling “self-evident” basic primitives and subjecting them to many different successive transformations and combiners. The process of doing so:

  1. Forces you to make explicit decisions about the structure of your computation type as an ADT.
  2. Allows you to retain isolation of fundamental parts of your domain as separate types
  3. Lets you manipulate the structure of your final computation type through normal Haskell techniques like pattern matching. The structure is available throughout the entire process, so you can replace individual components and values within your structure.
  4. Allows you to fully reflect the structure of your final computation through pattern matching and folds, so you can inspect the structure and produce useful summaries.

The main benefit of this library in specific is to allow you to be able to work with different functor combinators with a uniform and lawful interface, so the real functionality here is the wide variety of functor combinators from all around the Haskell ecosystem. This library does not provide the functor combinators, as much as it re-exports them with a unified interface. However, it does “fill in the matrix”, in a sense, of functor combinators in specific roles that are missing from the haskell ecosystem.

To jump into using it, import Data.Functor.Combinator. For a full introduction, check out the Functor Combinatorpedia, which goes in-depth into the motivation behind functor combinator-driven development, examples of the functor combinators in this library, and details about how to use these abstractions!


On the surface, functor-combinators look like it fills a similar space to effects systems and libraries like mtl, polysemy, freer-simple, or fused-effects. However, the functor combinator design pattern actually exists on a different level.

Functor combinator design patterns can be used to help build the structure of the data types and schemas that define your program/DSL. Once you build these nice structures, you then interpret them into some target context. This “target context” is the realm that libraries like mtl and polysemy can fill; functor combinators serve to help you define a structure for your program before you interpret it into whatever Applicative or Monad or effects system you end up using.




August 27, 2020

  • Data.HFunctor.HTraversable added, providing HTraversable and HTraversable1.
  • Control.Monad.Freer.Church: Missing Apply, Alt, and Plus instances added for Comp.
  • Data.HBifunctor: HFunctor instances for LeftF, RightF, Joker, Void3, and Comp made more kind-polymorphic
  • Data.HFunctor.Interpret: itraverse added, mimicking htraverse for proper Interpret instances.
  • Data.HFunctor.Chain: foldChainA and foldChain1A added, for effectful folding of chains.


August 15, 2020

  • DayChain and NightChain renamed to DivAp and DecAlt, to better reflect their abstracted nature ever since The modules are renamed to Data.Functor.Invariant.DivAp and Data.Functor.Invariant.DecAlt.

  • v0.3.5.1: Fixed infinite recursion bug for Tensor instances of invariant Day/Night.


August 14, 2020

  • Data.HFunctor.Route: A new twist on getting invariant functor combinators. Instead of creating new ones, utilize existing functor combinators with Pre/Post.

  • Data.Functor.Invariant.Day.Chain and Data.Functor.Invariant.Night.Chain created, factoring out the Chain part of the invariant Day/Night. This was done to fix the fact that Data.Functor.Invariant.Day is a module that already existed in kan-extensions. Oops!

    • As a consequence, DayChain and NightChain are now newtype wrappers instead of plain type synonyms.
  • v0.3.4.1: Add in missing Functor and Invariant instances for ProPre and ProPost, as well as a bunch of instances for ProPre.

  • v0.3.4.2: Add in missing HFunctor, Inject, Interpret instances for PostT.


August 11, 2020

  • Control.Applicative.ListF: Missing contravariant instances added for MaybeF.
  • Data.HFunctor: Add injectMap and injectContramap, two small utility functions that represent common patterns in injection and mapping.
  • Data.Functor.Combinator: Replace divideN and related functions with dsum and dsum1, which is an altogether cleaner interface that doesn’t require heterogenous lists. A part of a larger project on cleaning up Divisible tools.
  • Data.Functor.Contravariant.Divise: Add useful utility functions dsum and <:>, which makes the type of divise closer to that of <|> and asum.
  • Data.Functor.Contravariant.Divisible.Free: Implement Div in terms of a list, instead of the mirrored Ap. Should make it much easier to use, although a less-than-ideal Coyoneda is required to keep it compatible with the contravariant Day in kan-extensions. Added patterns to recover the original interface.


August 9, 2020

  • Data.HFunctor.Interpret: icollect, icollect1 now are more constrained: they only work on things that have Interpret instances for all Monoid m or Semigroup m in AltConst m. While this doesn’t affect how it works on any types in this library, it does make the type signature a little more clean (hiding the usage of DList) and prevents one from making an odd Interpret instance that does something weird with the DList. This also allows us to drop the direct dlist >= 1.0 dependency.
  • Data.HFunctor.Interpret: biapply, bifanout, bifanout1 added as contravariant consumer versions of iget, icollect, and icollect1.
  • Data.HBifunctor.Associative: bicollect bicollect1 removed because they really don’t make sense for associative tensors, which can only have at most one of each tensor.
  • Data.HBifunctor.Associative: biapply added as the contravariant consumer version of biget.
  • Data.Functor.Invariant.Day: Add conversion functions from chains to the covariant/invariant versions, chainAp, chainAp1, chainDiv, and chainDiv1.
  • Data.Functor.Invariant.Night: Add conversion functions from chains to the covariant/invariant versions, chainDec, chainDec1, chainListF, chainNonEmptyF. Also add “undescored” versions to the covariant versions, toCoNight_, chainListF_, chainNonEmptyF_, to more accurately represent the actual contravariant either-based day convolution. Also changed Share to Swerve.
  • Data.Functor.Combinator: AltConst re-exported.


August 7, 2020

  • Data.HFunctor.Interpret: getI and collectI made more efficient, and renamed to iget and icollect, respectively, to mirror biget and bicollect. getI and collectI are left in with a deprecation warning. icollect1 added to ensure a non-empty collection. AltConst added to aid in implementation.
  • Data.HBifunctor.Associative: bicollect1 added to ensure a non-empty collection. biget and bicollect made more efficient.
  • Data.Functor.Contravariant.Night, Data.Functor.Invariant.Night: refuted added for a convenient Not. Missing Invariant instance for Not also added.
  • Data.HFunctor.Chain: chainPair and chain1Pair renamed to toChain and toChain1, respectively, to mirror toListBy and toNonEmptyBy.


August 5, 2020

  • Data.HBifunctor.Associative, Data.HBifunctor.Tensor: Support for Contravariant and Invariant functor combinators. Main change to the infrastructure: add a FunctorBy associated constraint to Associative to signal what “sort of functor” the tensor supports: it should either be Unconstrained, Functor, Contravariant, or Invariant.

  • Data.Functor.Contravariant.Divise, Data.Functor.Contravariant.Decide, and Data.Functor.Contravariant.Conclude: Temporarily add in the semigroupoidal contravariant typeclasses. These should only be needed until they get merged into semigroupoids.

  • Data.Functor.Contravariant.Divisible: Add free structures for contravariant typeclass hierarchy.

  • Added in some new day convolutions:

    • Data.Functor.Contravariant.Night: Night, a contravariant day convolution using Either, which is the tensor that generates Conclude (and Decidable kinda).
    • Data.Functor.Invariant.Day: Day, an invariant day convolution using tuples.
    • Data.Functor.Invariant.Night: Night, an invariant day convolution using either.

    For the invariant day convolutions, we could write free monoids on them (like Ap/Div/Dec). But instead we just outsource our free structures to Chain, providing useful pattern synonyms and folding functions to pretend like we had an actual free structure.

  • Data.Functor.Combinator: Useful functions in for working with divisible and decidable contravariant functors: divideN, diviseN, concludeN, decideN, divideNRec, and diviseNRec.

  • Contravariant and Invariant instances for many types.

  • Data.HFunctor.Final: FreeOf adjusted to allow for contravariant free types.

  • Data.Functor.Combinator.Unsafe: Add unsafeDivise and unsafeConclude, to mirror the situation with unsafeApply and unsafePlus.


November 11, 2019

  • Major restructuring of the hbifunctor-based classes. Data.HBifunctor.Associative and Data.HBifunctor.Tensor are more or less completely rewritten; the typeclasses are restructured in order to more properly reflect the math that motivates them. See the updated type classes to see what methods ended up where.

    However, much of the external API that is independent of the underlying abstraction is effectively unchanged (biget, etc.)

    For the most part, the migration would involve:

    • SF, MF are now NonEmptyBy and ListBy, respectively.
    • -SF and -MF as suffixes for function names now become -NE and -LB.
  • upgradeC no longer exists; use unsafe functions from Data.Functor.Combinator.Unsafe instead, on a per-tensor basis.

  • Restructuring of Interpret: It now takes an extra type parameter, the type to interpret into. This makes it more consistent with the new MonoidIn and SemigroupIn. Most of the external API should be effectively unchanged.

    For the most part, the migration would only affect people who write instances of Interpret. Instead of

    instance Interpret MyType where
        type C MyType = Monad

    you would write:

    instance Monad f => Interpret MyType f where


July 13, 2019

  • Moved to trivial-constraints-


June 19, 2019

  • appendChain and appendChain1


June 19, 2019

  • Small tweaks for haddock generation and dependency bounds.


June 19, 2019

  • Initial release