{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE GADTs #-}
module Data.Dynamic.Resolve.Util where
import Data.Dynamic
import Type.Reflection
import GHC.Base (Type)
import Control.Monad (join)
import Data.Foldable (foldrM)
dynCons :: Dynamic
-> Dynamic
-> Maybe Dynamic
dynCons (Dynamic ta v) (Dynamic (App tl ta') vs)
| Just HRefl <- typeRep @[] `eqTypeRep` tl
, Just HRefl <- ta `eqTypeRep` ta'
= pure $ Dynamic (App tl ta) $ (v:vs)
dynCons (Dynamic tl _) (Dynamic tr _) = Nothing
dynPure :: forall env. (Applicative env, Typeable env)
=> Dynamic -> Dynamic
dynPure (Dynamic ta v) = (Dynamic (App (typeRep @env) ta) (pure v))
dynJoin :: forall env. (Monad env, Typeable env)
=> Dynamic -> Maybe Dynamic
dynJoin (Dynamic (App tf (App tf' ta)) v)
| Just HRefl <- typeRep @env `eqTypeRep` tf
, Just HRefl <- tf `eqTypeRep` tf'
= pure $ Dynamic (App tf ta) (join v)
dynJoin (Dynamic ta v) = Nothing
dynPureJoinId :: forall env. (Monad env, Typeable env)
=> Dynamic -> Dynamic
dynPureJoinId (Dynamic (App tf (App tf' ta)) v)
| Just HRefl <- typeRep @env `eqTypeRep` tf
, Just HRefl <- tf `eqTypeRep` tf'
= dynPureJoinId @env $ Dynamic (App tf ta) (join v)
dynPureJoinId d@(Dynamic (App tf ta) v) = d
dynPureJoinId d = dynPure @env d
dynEmptyList :: Dynamic -> Dynamic
dynEmptyList (Dynamic ta v) = Dynamic (App (typeRep @[]) ta) (tail [v])
dynMerge :: [Dynamic] -> Maybe Dynamic
dynMerge [] = Nothing
dynMerge (d:ds) = foldrM (dynCons) (dynEmptyList d) (d:ds)
dynMergeM :: forall f. (Monad f, Typeable f)
=> [Dynamic] -> Maybe Dynamic
dynMergeM [] = Nothing
dynMergeM ds = foldrM (dynCons) first normalized >>= dynSequence
where
tl = typeRep @[]
tf = typeRep @f
normalized@(n:_) = dynPureJoinId @f <$> ds
first = dynEmptyList n
dynSequence (Dynamic (App tl' (App tf' ta)) v)
| Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind ta
, Just HRefl <- tl `eqTypeRep` tl'
, Just HRefl <- tf `eqTypeRep` tf'
= pure $ Dynamic (App tf' (App tl' ta)) $ sequence v
dynSequence _ = Nothing
dynFmap :: forall f. (Functor f, Typeable f)
=> Dynamic
-> Dynamic
-> Maybe Dynamic
dynFmap (Dynamic (Fun ta tr) f) (Dynamic (App tf ta') x)
| Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind ta
, Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind tr
, Just HRefl <- ta `eqTypeRep` ta'
, Just HRefl <- typeRep @f `eqTypeRep` tf
= Just $ Dynamic (App tf tr) (f <$> x)
dynFmap _ _ = Nothing
dynAp :: forall f. (Applicative f, Typeable f)
=> Dynamic
-> Dynamic
-> Maybe Dynamic
dynAp (Dynamic (App tf (Fun ta tr)) f) (Dynamic (App tf' ta') x)
| Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind ta
, Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind tr
, Just HRefl <- ta `eqTypeRep` ta'
, Just HRefl <- typeRep @f `eqTypeRep` tf
, Just HRefl <- tf `eqTypeRep` tf'
= Just $ Dynamic (App tf tr) (f <*> x)
dynApplyFmapAp :: forall f. (Applicative f, Typeable f)
=> Dynamic
-> Dynamic
-> Maybe Dynamic
dynApplyFmapAp (Dynamic (App tf (Fun ta tr)) f) (Dynamic (App tf' ta') x)
| Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind ta
, Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind tr
, Just HRefl <- ta `eqTypeRep` ta'
, Just HRefl <- typeRep @f `eqTypeRep` tf
, Just HRefl <- tf `eqTypeRep` tf'
= Just $ Dynamic (App tf tr) (f <*> x)
dynApplyFmapAp (Dynamic (App tf (Fun ta tr)) f) (Dynamic ta' x)
| Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind ta
, Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind tr
, Just HRefl <- ta `eqTypeRep` ta'
, Just HRefl <- typeRep @f `eqTypeRep` tf
= Just $ Dynamic (App tf tr) (f <*> (pure x))
dynApplyFmapAp (Dynamic (Fun ta tr) f) (Dynamic (App tf ta') x)
| Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind ta
, Just HRefl <- typeRep @Type `eqTypeRep` typeRepKind tr
, Just HRefl <- ta `eqTypeRep` ta'
, Just HRefl <- typeRep @f `eqTypeRep` tf
= Just $ Dynamic (App tf tr) (f <$> x)
dynApplyFmapAp f x = dynApply f x