packages feed

apple-0.1.0.0: src/Ty/Clone.hs

{-# LANGUAGE RankNTypes #-}

module Ty.Clone ( cloneT ) where


import           A
import           Control.Monad.State.Strict (State, gets, runState)
import qualified Data.IntMap                as IM
import           Lens.Micro                 (Lens')
import           Lens.Micro.Mtl             (modifying, use)
import           Nm
import           U

data TR = TR { maxT    :: Int
             , boundTV :: IM.IntMap Int
             , boundSh :: IM.IntMap Int
             , boundIx :: IM.IntMap Int
             }

type CM = State TR

maxTLens :: Lens' TR Int
maxTLens f s = fmap (\x -> s { maxT = x }) (f (maxT s))

boundTVLens :: Lens' TR (IM.IntMap Int)
boundTVLens f s = fmap (\x -> s { boundTV = x }) (f (boundTV s))

boundShLens :: Lens' TR (IM.IntMap Int)
boundShLens f s = fmap (\x -> s { boundSh = x }) (f (boundSh s))

boundIxLens :: Lens' TR (IM.IntMap Int)
boundIxLens f s = fmap (\x -> s { boundIx = x }) (f (boundIx s))

-- for clone
freshen :: Lens' TR (IM.IntMap Int) -- ^ TVars, shape var, etc.
        -> Nm a -> CM (Nm a)
freshen lens (Nm n (U i) l) = do
    modifying maxTLens (+1)
    j <- gets maxT
    modifying lens (IM.insert i j)
    pure $ Nm n (U j) l

tryReplaceInT :: Lens' TR (IM.IntMap Int) -> Nm a -> CM (Nm a)
tryReplaceInT lens n@(Nm t (U i) l) = do
    st <- use lens
    case IM.lookup i st of
        Just j  -> pure (Nm t (U j) l)
        Nothing -> freshen lens n

cloneT :: Int -> T a
              -> (Int, T a, IM.IntMap Int) -- ^ Substition on type variables, returned so constraints can be propagated/copied
cloneT u = (\(t, TR uϵ tvs _ _) -> (uϵ,t,tvs)).flip runState (TR u IM.empty IM.empty IM.empty).cT
  where
    cloneIx :: I a -> CM (I a)
    cloneIx i@Ix{}           = pure i
    cloneIx (StaPlus l i i') = StaPlus l <$> cloneIx i <*> cloneIx i'
    cloneIx (StaMul l i i')  = StaMul l <$> cloneIx i <*> cloneIx i'
    cloneIx (IVar l n)       = IVar l <$> tryReplaceInT boundIxLens n
    cloneIx (IEVar l n)      = IEVar l <$> tryReplaceInT boundIxLens n

    cloneSh :: Sh a -> CM (Sh a)
    cloneSh Nil           = pure Nil
    cloneSh (Cons i sh)   = Cons <$> cloneIx i <*> cloneSh sh
    cloneSh (SVar n)      = SVar <$> tryReplaceInT boundShLens n
    cloneSh (Rev sh)      = Rev <$> cloneSh sh
    cloneSh (Cat sh0 sh1) = Cat <$> cloneSh sh0 <*> cloneSh sh1

    cT :: T a -> CM (T a)
    cT F            = pure F
    cT I            = pure I
    cT B            = pure B
    cT (Arrow t t') = Arrow <$> cT t <*> cT t'
    cT (Arr sh t)   = Arr <$> cloneSh sh <*> cT t
    cT (TVar n)     = TVar <$> tryReplaceInT boundTVLens n
    cT (P ts)       = P <$> traverse cT ts