Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instances for contravariant Coyoneda/Day #59

Open
thoughtpolice opened this issue Aug 19, 2019 · 0 comments
Open

Instances for contravariant Coyoneda/Day #59

thoughtpolice opened this issue Aug 19, 2019 · 0 comments

Comments

@thoughtpolice
Copy link

thoughtpolice commented Aug 19, 2019

I stumbled across these while implementing Termination Combinators Forever. The termination combinator type Test described therein is the contravariant Coyoneda transformation of the Equivalence functor. Its combinators are characterized by these instances: given Test a ~ Coyoneda Equivalence a, then chosen and divided are exactly the combinators eitherT and pairT, and conquer is alwaysT. These can then be derived automatically, all thanks to -XDerivingVia. (Equivalence technically demands symmetry which WQOs violate, but for deriving instances we can ignore it since we don't derive any others that need it.)

instance Divisible f => Divisible (Coyoneda f) where
  conquer :: Coyoneda f a
  conquer = Coyoneda id conquer
  {-# INLINE conquer #-}

  divide :: (a -> (b, c)) -> Coyoneda f b -> Coyoneda f c -> Coyoneda f a
  divide cleave (Coyoneda fb b) (Coyoneda fc c)
    = Coyoneda (bimap fb fc . cleave) (divided b c)
  {-# INLINE divide #-}

instance Decidable f => Decidable (Coyoneda f) where
  lose :: (a -> Void) -> Coyoneda f a
  lose f = Coyoneda id (lose f)
  {-# INLINE lose #-}

  choose :: (a -> Either b c) -> Coyoneda f b -> Coyoneda f c -> Coyoneda f a
  choose fork (Coyoneda fb b) (Coyoneda fc c)
    = Coyoneda (bimap fb fc . fork) (chosen b c)
  {-# INLINE choose #-}

Proof of equality is left as a simple exercise:

-- Generalized implementation of 'Test' from "Termination Combinators Forever"
newtype Test (a :: Type) = Test (Coyoneda Equivalence a)
  -- DerivingVia is amazing.
  deriving Contravariant via (Coyoneda Equivalence)
  deriving Divisible     via (Coyoneda Equivalence)
  deriving Decidable     via (Coyoneda Equivalence)

-- 'WQO' constructor, backwards-compatible with the
-- termination-combinators package/paper.
pattern WQO :: forall a. forall b. (a -> b) -> (b -> b -> Bool) -> Test a
pattern WQO co eq = Test (Coyoneda co (Equivalence eq))
{-# COMPLETE WQO #-}

Also, while playing around more, I stumbled upon the following instance for contravariant Day:

contract :: Divisible f => Day f f a -> f a
contract (Day ca cb k) = divide k ca cb

instance Divisible f => Divisible (Day f f) where
  conquer :: Day f f a
  conquer = diag conquer

  divide :: (a -> (b, c)) -> Day f f b -> Day f f c -> Day f f a
  divide cleave fb fc = Day (contract fb) (contract fc) cleave

I feel there is something lurking within Divisible (Day f f) that can get us to Divisible (Coyoneda f), but I'm not sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant