mstksg/functor-combinators

Indexed chain/listby & commutative bifunctors

Jashweii opened this issue · 0 comments

Disclaimer: I don't have a concrete use case for this, this is just a thought about how this library could cover the same ground as hlist/variant.

When you have a (directly) nested associative bifunctor application for a known finite spine a + b + c + d
there is often an efficient representation Variant '[a,b,c,d :: k -> Type] :: k -> Type. I.e. IListBy such that (exists n . IListBy t i (Replicate n a)) ~ ListBy t i a (for finite cases). I think you can always default to unsafely wrapping ListBy t GHC.Exts.Any when t is parametric in f. Would it make sense then to have type-indexed chains and lists in the library? E.g. (unchecked)

  -- foldr t i fs a, equivalent type supported by Tensor
  data IChain t i fs a where
    IDone :: i a -> IChain t i '[] a
    IMore :: t f (IChain t i fs) a -> IChain t i (f ': fs) a

  -- foldr1 t fs a, equivalent type supported by Associative
  -- basically the same as IChain t _ (_ ': fs)
  data IChain1 t fs a where
    IDone1 :: f a -> IChain1 t '[f] a
    IMore1 :: t f (IChain1 t fs) a -> IChain1 t (f ': fs) a  

Relatedly presumably there could be support for commutative bifunctors, which when associative might efficiently re-associate.

class HBifunctor t => Commutative t where
  hcommuting :: t f g <~> t g f

-- f is in fs at this index
newtype MemberOf fs f = UnsafeMemberOf Int

-- invariant: bijective. Groupoid instance
newtype Permutation fs gs = Permutation (MemberOf fs <~> MemberOf gs)

class (Commutative t, Associative t) => Abelian t where
  ipermuteNE :: Permutation fs gs -> INonEmptyBy t fs <~> INonEmptyBy t gs

class (Abelian t, Tensor t) => Monoid t where
  ipermute :: Permutation fs gs -> IListBy t fs <~> IListBy t gs

e.g.

  data IListBy (:+:) V1 fs a = forall f . IListByPlus1V1 !(MemberOf fs f) (f a)

Would just apply the permutation forwards to the index.

  data IListBy (:*:) U1 fs a = IListByTimes1U1 (forall f . MemberOf fs f -> f a)
  data IListBy These V1 fs a = IListByThese1V1 (forall f . MemberOf fs f -> Maybe (f a))

Would apply the inverse permutation to the input (function version for simplicity, alternatively a bunch of swaps/index changes)