ekmett/contravariant

Add ShowsPrec?

Zemyla opened this issue · 0 comments

The relevant type for Show is certainly a good Contravariant, Divisible, and Decidable:

newtype ShowsPrec a = ShowsPrec { runShowsPrec :: Int -> a -> ShowS }

instance Contravariant ShowsPrec where
    contramap f (ShowsPrec s) = ShowsPrec $ \p -> s p . f

instance Divisible ShowsPrec where
    conquer = ShowsPrec $ \_ _ -> id
    divide f (ShowsPrec sb) (ShowsPrec sc) = ShowsPrec $ \p -> uncurry (\b c -> sb p b . sc p c) . f

instance Decidable ShowsPrec where
    lose f = ShowsPrec $ \_ -> absurd . f
    choose f (ShowsPrec sb) (ShowsPrec sb) = ShowsPrec $ \p -> either (sb p) (sc p) . f

It also admits a number of useful combinators:

showCharP :: Char -> ShowsPrec a
showCharP c = ShowsPrec $ \_ _ -> showChar c

showStringP :: String -> ShowsPrec a
showStringP str = ShowsPrec $ \_ _ -> showString str

(>*) :: (Divisible f) => f () -> f a -> f a
(>*) = divide ((,) ())

(*<) :: (Divisible f) => f a -> f () -> f a
(*<) = divide (\a -> (a, ()))

parenP :: Int -> ShowsPrec a -> ShowsPrec a
parenP p0 (ShowsPrec sh) = ShowsPrec $ \p a -> showParen (p > p0) $ sh (p0 + 1) a

These are just examples, but it'd allow building up a ShowsPrec from smaller pieces, and fit with Equivalence and Comparison as "Contravariants arising from Prelude typeclasses".