packages feed

compaREST-0.1.0.0: src/Data/OpenUnion/Extra.hs

module Data.OpenUnion.Extra
  ( (@@>),
    TryLiftUnion (..),
    pattern SingletonUnion,
  )
where

import Control.Applicative
import Data.Dynamic
import Data.OpenUnion.Internal
import Data.Typeable
import TypeFun.Data.List hiding (Union)

class TryLiftUnion xs where
  tryLiftUnion :: (Alternative m, Typeable x) => x -> m (Union xs)

instance TryLiftUnion '[] where
  tryLiftUnion _ = empty

instance
  (Typeable y, SubList ys (y : ys), TryLiftUnion ys) =>
  TryLiftUnion (y ': ys)
  where
  tryLiftUnion (x :: x) = case eqT @x @y of
    Nothing -> reUnion <$> tryLiftUnion @ys x
    Just Refl -> pure $ liftUnion x

-- | Like '@>', but enforces a specific type list order.
-- (Useful for deconstruction-directed type inference.)
(@@>) :: Typeable a => (a -> b) -> (Union xs -> b) -> Union (a ': xs) -> b
r @@> l = either l r . restrict'
  where
    restrict' :: Typeable a => Union (a ': aa) -> Either (Union aa) a
    restrict' (Union d) = maybe (Left $ Union d) Right $ fromDynamic d
{-# INLINE (@@>) #-}

infixr 2 @@>

pattern SingletonUnion :: (Typeable a, Elem a s) => a -> Union s
pattern SingletonUnion x <-
  ((\(Union y) -> fromDynamic y) -> Just x)
  where
    SingletonUnion x = liftUnion x