{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.OpenADT.VarF where
import Control.Arrow ( (+++) )
import Data.Constraint
import Data.Functor.Classes
import Data.Functor.Const
import Data.Functor.Product
import Data.Maybe ( fromMaybe )
import Data.Proxy
import Data.Row
import Data.Row.Internal
import Data.Row.Variants
type family ApplyRow (x :: *) (r :: Row (* -> *)) :: Row * where
ApplyRow x ('R lt) = 'R (ApplyLT x lt)
type family ApplyLT (x :: *) (r :: [LT (* -> *)]) :: [LT *] where
ApplyLT _ '[] = '[]
ApplyLT x (l ':-> f ': fs) = ((l ':-> f x) ': ApplyLT x fs)
newtype VarF (r :: Row (* -> *)) x = VarF { unVarF :: Var (ApplyRow x r) }
deriving instance Forall (ApplyRow x r) Eq => Eq (VarF r x)
deriving instance Forall (ApplyRow x r) Show => Show (VarF r x)
newtype VarF' x (r :: Row (* -> *)) = VarF' { unVarF' :: Var (ApplyRow x r) }
newtype FlipApp (a :: *) (f :: * -> *) = FlipApp (f a)
mapVarF :: (Var (ApplyRow x u) -> Var (ApplyRow x v)) -> VarF u x -> VarF v x
mapVarF f (VarF v) = VarF (f v)
varFAlg
:: forall (c :: (* -> *) -> Constraint) (r :: Row (* -> *)) (x :: *) (y :: *)
. (Forall r c)
=> (forall f . (c f) => f x -> y)
-> VarF r x
-> y
varFAlg f =
getConst
. metamorph' @_ @r @c @(VarF' x) @(Const y) @(FlipApp x) Proxy
doNil
doUncons
doCons
. VarF'
. unVarF
where
doNil = impossible . unVarF'
doUncons l = (FlipApp +++ VarF') . flip trial l . unVarF'
doCons
:: forall ℓ τ ρ
. (c τ)
=> Label ℓ
-> Either (FlipApp x τ) (Const y ( 'R ρ))
-> Const y ( 'R (ℓ ':-> τ ': ρ))
doCons _ (Left (FlipApp v)) = Const (f v)
doCons _ (Right (Const y)) = Const y
varFAlg'
:: forall (r :: Row (* -> *)) (x :: *) (y :: *)
. (Forall r Unconstrained1)
=> (forall f . (Unconstrained1 f) => f x -> y)
-> VarF r x
-> y
varFAlg' = varFAlg @Unconstrained1 @r @x @y
type family RowFromTo (a :: Row *) (b :: *) :: Row * where
RowFromTo ('R r) b = 'R (RowFromToR r b)
type family RowFromToR (a :: [LT *]) (b :: *) :: [LT *] where
RowFromToR '[] x = '[]
RowFromToR (l ':-> a ': rs) b = l ':-> (a -> b) ': RowFromToR rs b
reduceVarF
:: forall r s t x r' s' t'
. ( t ≈ r .\\ s
, r' ~ ApplyRow x r
, s' ~ ApplyRow x s
, s' ≈ r' .\\ t'
, t' ≈ r' .\\ s'
, Disjoint s' t'
, Switch t' (RowFromTo t' (VarF s x)) (VarF s x)
)
=> Rec (RowFromTo t' (VarF s x))
-> VarF r x
-> VarF s x
reduceVarF f (VarF v) = case multiTrial @t' @r' v of
Left x -> caseon f x
Right x -> VarF x
instance Forall r Functor => Functor (VarF r) where
fmap :: forall a b. (a -> b) -> VarF r a -> VarF r b
fmap f = VarF . unVarF' . go . VarF' . unVarF
where
go = metamorph' @_ @r @Functor @(VarF' a) @(VarF' b) @(FlipApp a)
Proxy doNil doUncons doCons
doNil = impossible . unVarF'
doUncons l = (FlipApp +++ VarF') . flip trial l . unVarF'
doCons :: forall l f s. (KnownSymbol l, Functor f)
=> Label l
-> Either (FlipApp a f) (VarF' b ('R s))
-> VarF' b ('R (l ':-> f ': s))
doCons l (Left (FlipApp x)) = VarF' $ unsafeMakeVar l $ f <$> x
doCons _ (Right (VarF' v)) = VarF' $ unsafeInjectFront v
instance Forall r Eq1 => Eq1 (VarF r) where
liftEq :: forall a b. (a -> b -> Bool) -> VarF r a -> VarF r b -> Bool
liftEq f (VarF x) (VarF y) = fromMaybe False $ getConst $ metamorph' @_ @r @Eq1
@(Product (VarF' a) (VarF' b)) @(Const (Maybe Bool)) @(Const (Maybe Bool))
Proxy doNil doUncons doCons (Pair (VarF' x) (VarF' y))
where doNil :: Product (VarF' a) (VarF' b) Empty
-> Const (Maybe Bool) (Empty :: Row (* -> *))
doNil _ = Const Nothing
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, Eq1 τ)
=> Label ℓ
-> Product (VarF' a) (VarF' b) ('R (ℓ ':-> τ ': ρ))
-> Either (Const (Maybe Bool) τ)
(Product (VarF' a) (VarF' b) ('R ρ))
doUncons l (Pair (VarF' r1) (VarF' r2)) =
case (trial r1 l, trial r2 l) of
(Left u, Left v) -> Left $ Const $ Just $ liftEq f u v
(Right u, Right v) -> Right $ Pair (VarF' u) (VarF' v)
_ -> Left $ Const Nothing
doCons :: forall ℓ (τ :: * -> *) ρ
. Label ℓ
-> Either (Const (Maybe Bool) τ) (Const (Maybe Bool) ('R ρ))
-> Const (Maybe Bool) ('R (ℓ ':-> τ ': ρ))
doCons _ (Left (Const w)) = Const w
doCons _ (Right (Const w)) = Const w
instance Forall r Show1 => Show1 (VarF r) where
liftShowsPrec ::
forall a. (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> VarF r a -> ShowS
liftShowsPrec sa sl p =
let f :: forall f. (Show1 f) => f a -> ShowS
f x = showParen (p > 10) (showString "VarF " . liftShowsPrec sa sl p x)
in varFAlg @Show1 @r @a @ShowS f
type OpenAlg r l f v = ( ApplyRow v r .! l ≈ f v
, AllUniqueLabels (ApplyRow v r)
)