packages feed

stc-lang-1.0.0: src/Type/Magic/GHC8.hs

{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeApplications #-}

module Type.Magic.GHC8
    ( injectList
    , extractFunctor
    , extractList
    , injectFunctor
    ) where

import Control.Exception
import Data.Dynamic2 (Dynamic(..), TypeCastException(..))
import Data.Kind
import Type.Reflection
import Unsafe.Coerce

extractFunctor ::
       forall f. (Typeable f, Functor f)
    => Dynamic
    -> f Dynamic
extractFunctor =
    \case
        Dynamic (SomeTypeRep (App con tra)) dl ->
            case con `eqTypeRep` targetRep of
                Just HRefl -> fmap f $ unsafeCoerce dl
                Nothing ->
                    throw $
                    TypeCastException (SomeTypeRep con) (SomeTypeRep targetRep)
            where f = Dynamic (SomeTypeRep tra)
        Dynamic tr _ -> throw $ TypeCastException tr (SomeTypeRep targetRep)
  where
    targetRep = typeRep @f

extractList :: Dynamic -> [Dynamic]
extractList = extractFunctor

injectFunctor ::
       forall f. (Typeable f, Functor f)
    => Dynamic
    -> f Dynamic
    -> Dynamic
injectFunctor (Dynamic (SomeTypeRep tra) _) l =
    Dynamic tr $ unsafeCoerce $ fmap unwrap l
  where
    unwrap (Dynamic _ v) = v
    tr =
        case traKind `eqTypeRep` kindStar of
            Just HRefl -> SomeTypeRep $ App (typeRep @f) tra
            Nothing ->
                throw $
                TypeCastException (SomeTypeRep traKind) (SomeTypeRep kindStar)
      where
        traKind = typeRepKind tra
        kindStar = typeRep @Type

injectList :: [Dynamic] -> Dynamic
injectList [] = error "cannot convert empty list"
injectList l@(x:_) = injectFunctor x l