packages feed

row-types-barbies-1.0.0.0: src/Data/Row/Barbies.hs

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Row.Barbies
--
-- This module adds Barbies instances for 'Rec' and 'Var'.
--
-----------------------------------------------------------------------------


module Data.Row.Barbies () where

import           Data.Functor.Compose
import           Data.Functor.Identity
import           Data.Functor.Product
import           Data.Row
import           Data.Row.Dictionaries
import qualified Data.Row.Records      as Rec
import qualified Data.Row.Variants     as Var

import           Data.Functor.Barbie (FunctorB(..), TraversableB(..), DistributiveB(..), ApplicativeB(..), ConstraintsB(..))
import qualified Barbies.Constraints as B

-- | Barbies requires that the functor be the final argument of the type.  So,
-- even though the real type is @Rec (Map f ρ)@, we must wrap it in a newtype
-- wrapper so that 'f' is at the end.
newtype BarbieRec (ρ :: Row *) (f :: * -> *) = BarbieRec { unBarbieRec :: Rec (Rec.Map f ρ) }
newtype BarbieVar (ρ :: Row *) (f :: * -> *) = BarbieVar { unBarbieVar :: Var (Var.Map f ρ) }

instance FreeForall r => FunctorB (BarbieRec r) where
  bmap f = BarbieRec . Rec.transform' @r f . unBarbieRec

instance FreeForall r => TraversableB (BarbieRec r) where
  btraverse :: forall e f g. Applicative e => (forall a. f a -> e (g a)) -> BarbieRec r f -> e (BarbieRec r g)
  btraverse f  = fmap BarbieRec . Rec.traverseMap @Unconstrained1 @e @f @g @r f . unBarbieRec

instance FreeForall r => DistributiveB (BarbieRec r) where
  bdistribute :: forall f g. Functor f => f (BarbieRec r g) -> BarbieRec r (Compose f g)
  bdistribute = BarbieRec . Rec.compose @f @g @r . Rec.distribute @f @(Rec.Map g r) . fmap unBarbieRec
    \\ freeForall @(Rec.Map g r) @(IsA Unconstrained1 g) \\ mapForall @g @r @Unconstrained1

instance (AllUniqueLabels r, FreeForall r) => ApplicativeB (BarbieRec r) where
  bpure :: forall f. (forall a. f a) -> BarbieRec r f
  bpure fa = BarbieRec $ runIdentity $ Rec.fromLabelsMapA @Unconstrained1 @Identity @f @r (const $ Identity fa)

  bprod :: forall f g. BarbieRec r f -> BarbieRec r g -> BarbieRec r (f `Product` g)
  bprod (BarbieRec r1) (BarbieRec r2) = BarbieRec $ Rec.zipTransform @Unconstrained1 @r @f @g @(Product f g) Pair r1 r2

instance FreeForall r => ConstraintsB (BarbieRec r) where
  type AllB c (BarbieRec r) = Forall r c
  baddDicts :: forall c f. Forall r c => BarbieRec r f -> BarbieRec r (B.Dict c `Product` f)
  baddDicts = BarbieRec . Rec.transform @c @r @f @(B.Dict c `Product` f) (Pair (B.Dict @c)) . unBarbieRec



instance FreeForall r => FunctorB (BarbieVar r) where
  bmap f = BarbieVar . Var.transform' @r f . unBarbieVar

instance FreeForall r => TraversableB (BarbieVar r) where
  btraverse :: forall e f g. Applicative e => (forall a. f a -> e (g a)) -> BarbieVar r f -> e (BarbieVar r g)
  btraverse f  = fmap BarbieVar . Var.traverseMap @Unconstrained1 @e @f @g @r f . unBarbieVar

instance FreeForall r => ConstraintsB (BarbieVar r) where
  type AllB c (BarbieVar r) = Forall r c
  baddDicts :: forall c f. Forall r c => BarbieVar r f -> BarbieVar r (B.Dict c `Product` f)
  baddDicts = BarbieVar . Var.transform @c @r @f @(B.Dict c `Product` f) (Pair (B.Dict @c)) . unBarbieVar