newtype F m f a = F (f a -> m)
Icelandjack opened this issue · 4 comments
Something like this generalizes
newtype F m f a = F (f a -> m)
instance Functor f => Contravariant (F m f) where
contramap :: (a' -> a) -> (F m f a -> F m f a')
contramap f (F g) = F (\fa -> g (fmap f fa))
instance (Monoid m, Functor f) => Divisible (F m f) where
conquer :: F m f a
conquer = F $ const mempty
divide :: (a -> (b, c)) -> (F m f b -> F m f c -> F m f a)
divide split (F left) (F right) = F $ \(fmap split -> fbc) ->
left (fst <$> fbc) <> right (snd <$> fbc)
where
newtype Predicate a = Predicate_ (F All Identity a)
newtype Comparison a = Comparison_ (F Ordering V2 a)
newtype Equivalence a = Equivalence_ (F All V2 a)
One of these days I'm expecting to see you write
newtype NewType a = NewType (Deriving Kitchen Sink Plus NewType a) deriving (.*)
F m f a = Flip (Costar f) m a
, have you tried implementing Divisible (Flip p m)
with some constraints on p
?
Edit: I think you need forall a. Monoid (p a m)
, annoyingly.
Also this first needs an instance Profunctor p => Contravariant (Flip p a)
, which could only live in the profunctor package because profunctor
depends on contravariant
, but that would be an orphan instance...
@ocharles Be careful!
@sjoerdvisscher My gut tells me it should be its own thing, forall xx. Monoid (p xx m)
could be a way forward once we have quantified constraints or maybe there is a totally different constraint that makes sense, I would have to think about it.
I wasn't successful in generalizing it to Decidable
, lose
seems to require a Comonad
constraint but I got stuck on choose
instance (Monoid m, Comonad f) => Decidable (F m f) where
lose :: (a -> Void) -> F m f a
lose f = F (absurd . f . extract)
choose :: (a -> Either b c) -> (F m f b -> F m f c -> F m f a)
choose split = ???
The part I'm unsure how to achieve (generically) is producing LT
and GT
,
choose :: forall a b c. (a -> Either b c) -> (Comparison b -> Comparison c -> Comparison a)
choose split (Comparison left) (Comparison right) = Comparison (\a a' -> split a * split a')
where
(*) :: Either b c -> Either b c -> Ordering
Left b * Left b' = left b b'
Right c * Right c' = right c c'
Left{} * Right{} = LT
Right{} * Left{} = GT
one way (that requires an Ord
constraint for b
, c
) is compare Left{} Right{} = LT
but meh
In my experience, if you have an Applicative instance that requires a Monoid, then there can be an instance for Alternative if you switch to a semiring, where the multiplicative monoid gives the Applicative instance and the additive monoid the Alternative one.
Maybe the same works here?