module Data.OpenUnion1.Clean (Union, Nil, List(..), (|>)(..), (@>), exhaust, (∈)(), Member, liftU, (⊆)(..), Include) where
import Data.Proxy
data List a = Empty | a :> List a
infixr 5 :>
infixr 5 |>
type family (f :: * -> *) |> (s :: * -> *) :: * -> *
type instance f |> Union s = Union (f :> s)
type Nil = Union Empty
data family Union (s :: List (* -> *)) a
data instance Union (f :> s) a = Single (f a) | Union (Union s a)
data instance Union Empty a = Exhausted (Union Empty a)
(@>) :: (f x -> r)
-> (Union s x -> r)
-> (Union (f :> s) x -> r)
(@>) run _ (Single f) = run f
(@>) _ cont (Union r) = cont r
infixr 0 @>
exhaust :: Nil x -> m r
exhaust (Exhausted a) = exhaust a
data MemberInfo f s where
Head :: MemberInfo f (f :> s)
Tail :: (f ∈ s) => MemberInfo f (g :> s)
class f ∈ s where
query :: Proxy f -> Proxy s -> MemberInfo f s
infix 4 ∈
infix 4 ⊆
instance f ∈ (f :> s) where query _ _ = Head
instance (f ∈ s) => f ∈ (g :> s) where query _ _ = Tail
liftU :: forall s f a. (f ∈ s) => f a -> Union s a
liftU f = case query (Proxy :: Proxy f) (Proxy :: Proxy s) of
Head -> Single f
Tail -> Union (liftU f)
class s ⊆ t where
reunion :: Union s a -> Union t a
instance (f ∈ t, s ⊆ t) => (f :> s) ⊆ t where
reunion (Single f) = liftU f
reunion (Union s) = reunion s
instance Empty ⊆ t where
reunion = exhaust
type Member f s = f ∈ s
type Include s t = s ⊆ t