{-# LANGUAGE UndecidableInstances, GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleInstances, TemplateHaskell, EmptyCase #-}
module AST.Term.NamelessScope
( Scope(..), _Scope, KWitness(..)
, ScopeVar(..), _ScopeVar
, EmptyScope
, DeBruijnIndex(..)
, ScopeTypes(..), _ScopeTypes, HasScopeTypes(..)
) where
import AST
import AST.Class.Infer.Infer1
import AST.Infer
import AST.Term.FuncType
import AST.Unify (Unify(..), UVarOf)
import AST.Unify.New (newUnbound)
import Control.Lens (Lens', Prism')
import qualified Control.Lens as Lens
import Control.Lens.Operators
import Control.Monad.Reader (MonadReader, local)
import Data.Constraint
import Data.Sequence (Seq)
import qualified Data.Sequence as Sequence
import Data.Proxy (Proxy(..))
import Prelude.Compat
data EmptyScope
newtype Scope expr a k = Scope (k # expr (Maybe a))
Lens.makePrisms ''Scope
newtype ScopeVar (expr :: * -> Knot -> *) a (k :: Knot) = ScopeVar a
Lens.makePrisms ''ScopeVar
makeZipMatch ''Scope
makeKTraversableApplyAndBases ''Scope
makeZipMatch ''ScopeVar
makeKTraversableApplyAndBases ''ScopeVar
class DeBruijnIndex a where
deBruijnIndex :: Prism' Int a
instance DeBruijnIndex EmptyScope where
deBruijnIndex = Lens.prism (\case{}) Left
instance DeBruijnIndex a => DeBruijnIndex (Maybe a) where
deBruijnIndex =
Lens.prism' toInt fromInt
where
toInt Nothing = 0
toInt (Just x) = 1 + deBruijnIndex # x
fromInt x
| x == 0 = Just Nothing
| otherwise = (x - 1) ^? deBruijnIndex <&> Just
newtype ScopeTypes t v = ScopeTypes (Seq (v # t))
deriving newtype (Semigroup, Monoid)
Lens.makePrisms ''ScopeTypes
makeKTraversableApplyAndBases ''ScopeTypes
class HasScopeTypes v t env where
scopeTypes :: Lens' env (Tree (ScopeTypes t) v)
instance HasScopeTypes v t (Tree (ScopeTypes t) v) where
scopeTypes = id
type instance InferOf (Scope t k) = FuncType (TypeOf (t k))
type instance InferOf (ScopeVar t k) = ANode (TypeOf (t k))
instance HasTypeOf1 t => HasInferOf1 (Scope t) where
type InferOf1 (Scope t) = FuncType (TypeOf1 t)
type InferOf1IndexConstraint (Scope t) = DeBruijnIndex
hasInferOf1 p =
withDict (typeAst (p0 p)) Dict
where
p0 :: Proxy (Scope t k) -> Proxy (t k)
p0 _ = Proxy
instance
( Infer1 m t
, HasInferOf1 t
, InferOf1IndexConstraint t ~ DeBruijnIndex
, DeBruijnIndex k
, Unify m (TypeOf (t k))
, MonadReader env m
, HasScopeTypes (UVarOf m) (TypeOf (t k)) env
, HasInferredType (t k)
) =>
Infer m (Scope t k) where
inferBody (Scope x) =
withDict (hasInferOf1 (Proxy @(t k))) $
withDict (hasInferOf1 (Proxy @(t (Maybe k)))) $
do
varType <- newUnbound
inferChild x
& local (scopeTypes . _ScopeTypes %~ (varType Sequence.<|))
<&>
\(InferredChild xI xR) ->
( Scope xI
, FuncType varType (xR ^# inferredType (Proxy @(t k)))
)
\\ (inferMonad :: DeBruijnIndex (Maybe k) :- Infer m (t (Maybe k)))
inferContext _ _ =
Dict \\ inferMonad @m @t @(Maybe k)
instance
( MonadReader env m
, HasScopeTypes (UVarOf m) (TypeOf (t k)) env
, DeBruijnIndex k
, Unify m (TypeOf (t k))
) =>
Infer m (ScopeVar t k) where
inferBody (ScopeVar v) =
Lens.view (scopeTypes . _ScopeTypes)
<&> (^?! Lens.ix (deBruijnIndex # v))
<&> MkANode
<&> (ScopeVar v, )