packages feed

opaleye-0.6.7005.0: Test/Wrapped.hs

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE GADTs #-}

module Wrapped where

import           Control.Arrow (arr, (<<<))
import qualified Control.Arrow as Arrow
import qualified Control.Category
import           Control.Category (Category)
import qualified Data.Functor.Contravariant as C
import qualified Data.Functor.Contravariant.Divisible as D
import qualified Data.Profunctor as P
import qualified Data.Profunctor.Product as PP

data WrappedSumProfunctor p a b where
  WrappedSumProfunctor        :: p a b -> WrappedSumProfunctor p a b
  WrappedSumProfunctorId      :: WrappedSumProfunctor p a a
  WrappedSumProfunctorArr     :: (a -> b) -> WrappedSumProfunctor p a b
  WrappedSumProfunctorCompose :: WrappedSumProfunctor p b c
                              -> WrappedSumProfunctor p a b
                              -> WrappedSumProfunctor p a c
  WrappedSumProfunctorChoice  ::
       WrappedSumProfunctor p a a'
    -> WrappedSumProfunctor p b b'
    -> WrappedSumProfunctor p (Either a b) (Either a' b')

newtype WrappedDecidable f a b =
  WrappedDecidable { unWrappedDecidable :: f a }

instance C.Contravariant f => P.Profunctor (WrappedDecidable f) where
  dimap f _ = WrappedDecidable . C.contramap f . unWrappedDecidable

instance D.Decidable f => PP.SumProfunctor (WrappedDecidable f) where
  f1 +++! f2 =
    WrappedDecidable (D.choose id (unWrappedDecidable f1)
                                  (unWrappedDecidable f2))

constructor :: P.Profunctor p
            => (b -> c) -> p a b -> WrappedSumProfunctor p a c
constructor c p = P.rmap c (WrappedSumProfunctor p)

constructorDecidable :: D.Decidable f
                     => f a
                     -> WrappedSumProfunctor (WrappedDecidable f) a c
constructorDecidable f = WrappedSumProfunctor (WrappedDecidable f)

asSumProfunctor :: PP.SumProfunctor p
                => WrappedSumProfunctor p a b -> p a b
asSumProfunctor w = case unWrappedSumProfunctorE w of
  Left p  -> p
  Right _ -> error "unWrappedSumProfunctor was function"

asDecidable :: D.Decidable f
            => WrappedSumProfunctor (WrappedDecidable f) a b -> f a
asDecidable = unWrappedDecidable . asSumProfunctor

unWrappedSumProfunctorE :: PP.SumProfunctor p
                        => WrappedSumProfunctor p a b -> Either (p a b) (a -> b)
unWrappedSumProfunctorE = \case
  WrappedSumProfunctor p    -> Left p
  WrappedSumProfunctorId    -> Right id
  WrappedSumProfunctorArr f -> Right f
  WrappedSumProfunctorCompose w1 w2 ->
    case (unWrappedSumProfunctorE w1, unWrappedSumProfunctorE w2) of
      (Left _, Left _)     -> error "Composing two profunctors"
      (Right f, Left p)    -> Left (P.rmap f p)
      (Left p, Right f)    -> Left (P.lmap f p)
      (Right f1, Right f2) -> Right (f1 . f2)

  WrappedSumProfunctorChoice w1 w2 ->
    case (unWrappedSumProfunctorE w1, unWrappedSumProfunctorE w2) of
      (Left p1, Left p2) -> Left (p1 PP.+++! p2)
      _ -> error "WrappedSumProfunctorChoice"

instance Category (WrappedSumProfunctor p) where
  id  = WrappedSumProfunctorId
  (.) = WrappedSumProfunctorCompose

instance Arrow.Arrow (WrappedSumProfunctor p) where
  arr   = WrappedSumProfunctorArr
  first = error "WrappedSumProfunctor first"

instance PP.SumProfunctor p => Arrow.ArrowChoice (WrappedSumProfunctor p) where
  (+++) = WrappedSumProfunctorChoice

instance P.Profunctor p => P.Profunctor (WrappedSumProfunctor p) where
  dimap f g w = arr g <<< w <<< arr f