heftia-0.1.0.0: src/Data/Hefty/Union.hs
{-# LANGUAGE UndecidableInstances #-}
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.
{- |
Copyright : (c) 2023 Yamada Ryo
License : MPL-2.0 (see the file LICENSE)
Maintainer : ymdfield@outlook.jp
Stability : experimental
Portability : portable
A type class representing a general open union for higher-order effects, independent of the internal
implementation.
-}
module Data.Hefty.Union where
import Control.Effect.Class (Signature, type (~>))
import Data.Kind (Constraint)
{- |
A type class representing a general open union for higher-order effects, independent of the internal
implementation.
-}
class UnionH (u :: [Signature] -> Signature) where
{-# MINIMAL injectH, projectH, absurdUnionH, (compH | (inject0H, weakenH), decompH | (|+:)) #-}
type HasMembershipH u (h :: Signature) (hs :: [Signature]) :: Constraint
injectH :: HasMembershipH u h hs => h f ~> u hs f
projectH :: HasMembershipH u h hs => u hs f a -> Maybe (h f a)
absurdUnionH :: u '[] f a -> x
compH :: Either (h f a) (u hs f a) -> u (h ': hs) f a
compH = \case
Left x -> inject0H x
Right x -> weakenH x
{-# INLINE compH #-}
decompH :: u (h ': hs) f a -> Either (h f a) (u hs f a)
decompH = Left |+: Right
{-# INLINE decompH #-}
infixr 5 |+:
(|+:) :: (h f a -> r) -> (u hs f a -> r) -> u (h ': hs) f a -> r
(f |+: g) u = case decompH u of
Left x -> f x
Right x -> g x
{-# INLINE (|+:) #-}
inject0H :: h f ~> u (h ': hs) f
inject0H = compH . Left
{-# INLINE inject0H #-}
injectUnderH :: h2 f ~> u (h1 ': h2 ': hs) f
injectUnderH = weakenH . inject0H
{-# INLINE injectUnderH #-}
injectUnder2H :: h3 f ~> u (h1 ': h2 ': h3 ': hs) f
injectUnder2H = weaken2H . inject0H
{-# INLINE injectUnder2H #-}
injectUnder3H :: h4 f ~> u (h1 ': h2 ': h3 ': h4 ': hs) f
injectUnder3H = weaken3H . inject0H
{-# INLINE injectUnder3H #-}
weakenH :: u hs f ~> u (h ': hs) f
weakenH = compH . Right
{-# INLINE weakenH #-}
weaken2H :: u hs f ~> u (h1 ': h2 ': hs) f
weaken2H = weakenH . weakenH
{-# INLINE weaken2H #-}
weaken3H :: u hs f ~> u (h1 ': h2 ': h3 ': hs) f
weaken3H = weaken2H . weakenH
{-# INLINE weaken3H #-}
weaken4H :: u hs f ~> u (h1 ': h2 ': h3 ': h4 ': hs) f
weaken4H = weaken3H . weakenH
{-# INLINE weaken4H #-}
weakenUnderH :: u (h1 ': hs) f ~> u (h1 ': h2 ': hs) f
weakenUnderH = inject0H |+: weaken2H
weakenUnder2H :: u (h1 ': h2 ': hs) f ~> u (h1 ': h2 ': h3 ': hs) f
weakenUnder2H = inject0H |+: injectUnderH |+: weaken3H
weakenUnder3H :: u (h1 ': h2 ': h3 ': hs) f ~> u (h1 ': h2 ': h3 ': h4 ': hs) f
weakenUnder3H = inject0H |+: injectUnderH |+: injectUnder2H |+: weaken4H
weaken2UnderH :: u (h1 ': hs) f ~> u (h1 ': h2 ': h3 ': hs) f
weaken2UnderH = inject0H |+: weaken3H
weaken2Under2H :: u (h1 ': h2 ': hs) f ~> u (h1 ': h2 ': h3 ': h4 ': hs) f
weaken2Under2H = inject0H |+: injectUnderH |+: weaken4H
weaken3UnderH :: u (h1 ': hs) f ~> u (h1 ': h2 ': h3 ': h4 ': hs) f
weaken3UnderH = inject0H |+: weaken4H
flipUnionH :: u (h1 ': h2 ': hs) f ~> u (h2 ': h1 ': hs) f
flipUnionH = injectUnderH |+: inject0H |+: weaken2H
flipUnion3H :: u (h1 ': h2 ': h3 ': hs) f ~> u (h3 ': h2 ': h1 ': hs) f
flipUnion3H = injectUnder2H |+: injectUnderH |+: inject0H |+: weaken3H
flipUnionUnderH :: u (h1 ': h2 ': h3 ': hs) f ~> u (h1 ': h3 ': h2 ': hs) f
flipUnionUnderH = inject0H |+: injectUnder2H |+: injectUnderH |+: weaken3H
rot3H :: u (h1 ': h2 ': h3 ': hs) f ~> u (h2 ': h3 ': h1 ': hs) f
rot3H = injectUnder2H |+: inject0H |+: injectUnderH |+: weaken3H
rot3H' :: u (h1 ': h2 ': h3 ': hs) f ~> u (h3 ': h1 ': h2 ': hs) f
rot3H' = injectUnderH |+: injectUnder2H |+: inject0H |+: weaken3H
bundleUnion2H :: UnionH u' => u (h1 ': h2 ': hs) f ~> u (u' '[h1, h2] ': hs) f
bundleUnion2H = inject0H . inject0H |+: inject0H . injectUnderH |+: weakenH
bundleUnion3H :: UnionH u' => u (h1 ': h2 ': h3 ': hs) f ~> u (u' '[h1, h2, h3] ': hs) f
bundleUnion3H =
(inject0H . inject0H)
|+: (inject0H . injectUnderH)
|+: (inject0H . injectUnder2H)
|+: weakenH
bundleUnion4H ::
UnionH u' =>
u (h1 ': h2 ': h3 ': h4 ': hs) f ~> u (u' '[h1, h2, h3, h4] ': hs) f
bundleUnion4H =
(inject0H . inject0H)
|+: (inject0H . injectUnderH)
|+: (inject0H . injectUnder2H)
|+: (inject0H . injectUnder3H)
|+: weakenH
unbundleUnion2H :: UnionH u' => u (u' '[h1, h2] ': hs) f ~> u (h1 ': h2 ': hs) f
unbundleUnion2H = (inject0H |+: injectUnderH |+: absurdUnionH) |+: weaken2H
unbundleUnion3H :: UnionH u' => u (u' '[h1, h2, h3] ': hs) f ~> u (h1 ': h2 ': h3 ': hs) f
unbundleUnion3H = (inject0H |+: injectUnderH |+: injectUnder2H |+: absurdUnionH) |+: weaken3H
unbundleUnion4H ::
UnionH u' =>
u (u' '[h1, h2, h3, h4] ': hs) f
~> u (h1 ': h2 ': h3 ': h4 ': hs) f
unbundleUnion4H =
(inject0H |+: injectUnderH |+: injectUnder2H |+: injectUnder3H |+: absurdUnionH)
|+: weaken4H
type family IsMemberH (h :: Signature) hs where
IsMemberH h (h ': hs) = 'True
IsMemberH h (_ ': hs) = IsMemberH h hs
IsMemberH _ '[] = 'False
type MemberH u h hs = (HasMembershipH u h hs, IsMemberH h hs ~ 'True)