{-# LANGUAGE CPP #-}
{-# LANGUAGE UndecidableInstances #-}
#ifndef MIN_VERSION_GLASGOW_HASKELL
#define MIN_VERSION_GLASGOW_HASKELL(a,b,c,d) 0
#endif
#if MIN_VERSION_GLASGOW_HASKELL(7,10,0,0)
#else
{-# LANGUAGE OverlappingInstances #-}
#endif
module Language.Syntactic.Functional.WellScoped where
import Control.Monad.Reader
import Data.Proxy
import Language.Syntactic
import Language.Syntactic.Functional
class Ext ext orig
where
unext :: ext -> orig
diff :: Num a => Proxy ext -> Proxy orig -> a
instance {-# OVERLAPPING #-} Ext env env
where
unext = id
diff _ _ = 0
instance {-# OVERLAPPING #-} (Ext env e, ext ~ (a,env)) => Ext ext e
where
unext = unext . snd
diff m n = diff (fmap snd m) n + 1
lookEnv :: forall env a e . Ext env (a,e) => Proxy e -> Reader env a
lookEnv _ = reader $ \env -> let (a, _ :: e) = unext env in a
data BindingWS sig
where
VarWS :: Ext env (a,e) => Proxy e -> BindingWS (Full (Reader env a))
LamWS :: BindingWS (Reader (a,e) b :-> Full (Reader e (a -> b)))
instance Symbol BindingWS
where
symSig (VarWS _) = signature
symSig LamWS = signature
instance NFData1 BindingWS
where
liftRnf _ (VarWS Proxy) = ()
liftRnf _ LamWS = ()
instance Eval BindingWS
where
evalSym (VarWS p) = lookEnv p
evalSym LamWS = \f -> reader $ \e -> \a -> runReader f (a,e)
lamWS :: forall a e sym b . (BindingWS :<: sym)
=> ((forall env . (Ext env (a,e)) => ASTF sym (Reader env a)) -> ASTF sym (Reader (a,e) b))
-> ASTF sym (Reader e (a -> b))
lamWS f = smartSym LamWS $ f $ smartSym (VarWS (Proxy :: Proxy e))
evalOpenWS :: Eval s => env -> ASTF s (Reader env a) -> a
evalOpenWS e = ($ e) . runReader . evalDen
evalClosedWS :: Eval s => ASTF s (Reader () a) -> a
evalClosedWS = evalOpenWS ()
type family LiftReader env sig
type instance LiftReader env (Full a) = Full (Reader env a)
type instance LiftReader env (a :-> sig) = Reader env a :-> LiftReader env sig
type family UnReader a
type instance UnReader (Reader e a) = a
type family LowerReader sig
type instance LowerReader (Full a) = Full (UnReader a)
type instance LowerReader (a :-> sig) = UnReader a :-> LowerReader sig
data ReaderSym sym sig
where
ReaderSym
:: ( Signature sig
, Denotation (LiftReader env sig) ~ DenotationM (Reader env) sig
, LowerReader (LiftReader env sig) ~ sig
)
=> Proxy env
-> sym sig
-> ReaderSym sym (LiftReader env sig)
instance Eval sym => Eval (ReaderSym sym)
where
evalSym (ReaderSym (_ :: Proxy env) s) = liftDenotationM signature p s $ evalSym s
where
p = Proxy :: Proxy (Reader env)
type WS sym env a = ASTF (BindingWS :+: ReaderSym sym) (Reader env a)
fromWS :: WS sym env a -> ASTF (Binding :+: sym) a
fromWS = fromDeBruijn . go
where
go :: AST (BindingWS :+: ReaderSym sym) sig -> AST (Binding :+: sym) (LowerReader sig)
go (Sym (InjL s@(VarWS p))) = Sym (InjL (Var (diff (mkProxy2 s) (mkProxy1 s p))))
where
mkProxy1 = (\_ _ -> Proxy) :: BindingWS (Full (Reader e' a)) -> Proxy e -> Proxy (a,e)
mkProxy2 = (\_ -> Proxy) :: BindingWS (Full (Reader e' a)) -> Proxy e'
go (Sym (InjL LamWS)) = Sym $ InjL $ Lam (-1)
go (s :$ a) = go s :$ go a
go (Sym (InjR (ReaderSym _ s))) = Sym $ InjR s
smartWS :: forall sig sig' bsym f sub sup env a
. ( Signature sig
, Signature sig'
, sub :<: sup
, bsym ~ (BindingWS :+: ReaderSym sup)
, f ~ SmartFun bsym sig'
, sig' ~ SmartSig f
, bsym ~ SmartSym f
, sig' ~ LiftReader env sig
, Denotation (LiftReader env sig) ~ DenotationM (Reader env) sig
, LowerReader (LiftReader env sig) ~ sig
, Reader env a ~ DenResult sig'
)
=> sub sig -> f
smartWS s = smartSym' $ InjR $ ReaderSym (Proxy :: Proxy env) $ inj s