kindly-functors: A category polymorphic `Functor` typeclass

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

A category polymorphic Functor typeclass.

[Skip to Readme]


Change log
Dependencies base (>4 && <5), mtl (>=2.2.2 && <2.4), profunctors (>=5.6.2 && <5.7), semigroupoids (>=6.0.0 && <6.1), these (>=1.2 && <1.3), witherable (>=0.4.2 && <0.5) [details]
License MIT
Author Solomon Bothwell
Category Control, Categories
Home page
Uploaded by solomon at 2024-02-05T04:08:47Z


[Index] [Quick Jump]


Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Readme for kindly-functors-

[back to package description]

Kindly Functors


kindly-functors::CI kindly-functors::CI

A category polymorphic Functor typeclass based on the work of IcelandJack and Ed Kmett allowing you to pick out arbitrary kinds and variances for your functors.

This library offers direct access to the FunctorOf and Functor classes defined in the above work but also a slightly more familiar API for one, two, and three parameter functors.

type Functor f = FunctorOf (->) (->)
type Contravariant f = FunctorOf Op (->)
type Invariant f = FunctorOf (<->) (->)
type Filterable f = FunctorOf (Star Maybe) (->)
type Bifunctor p = FunctorOf (->) (Nat (->) (->))
type Profunctor p = FunctorOf Op (Nat (->) (->))
type Trifunctor p = FunctorOf cat1 (Nat cat2 (Nat cat3 cat4))

fmap, bimap, lmap, and rmap have been made polymorphic over variances:

> fmap show (Identity True)
Identity "True"

> getPredicate (fmap (Op read) (Predicate not)) "True"

> lmap show (True, False)

> lmap (Op read) not "True"

> rmap show (True, False)

> bimap show read (Left True)
Left "True"

> bimap (read @Int) show ("1", True)

> bimap (Op (read @Int)) show (+1) "0"

> trimap show show show (True, False, ())

How does this work?

The above functions are all just instantions of map1, map2, and map3:

> map1 show (True, False, ())

> map1 show (Left True)
Left True

> map2 show (True, False, ())

> map3 show (True, False, ())

Becareful when using these directly as GHC might pick out a surprising instance:

> map2 show (Left True)
Left "True"

These functions themselves are a frontend for map from the (kindly) Functor class:

type Functor :: (from -> to) -> Constraint
class (Category (Dom f), Category (Cod f)) => Functor (f :: from -> to) where
  type Dom f :: from -> from -> Type
  type Cod f :: to -> to -> Type

  map :: Dom f a b -> Cod f (f a) (f b)

-- NOTE: These these classes are labeled from right to left:
class (FunctorOf cat (->) p) => MapArg1 cat p | p -> cat where
  map1 :: (a `cat` b) -> p a -> p b
  map1 = map

class (FunctorOf cat1 (cat2 ~> (->)) p) => MapArg2 cat1 cat2 p | p -> cat2 cat2 where
  map2 :: (a `cat1` b) -> forall x. p a x -> p b x
  map2 = runNat . map

class (FunctorOf cat1 (cat2 ~> cat3 ~> (->)) p) => MapArg3 cat1 cat2 cat3 p | p -> cat1 cat2 cat3 where
  map3 :: (a `cat1` b) -> forall x y. p a x y -> p b x y
  map3 f = runNat (runNat (map f))