{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UnicodeSyntax #-} module Abt.Concrete.LocallyNameless ( Tm(..) , Tm0 , _TmOp , Var(..) , varName , varIndex ) where import Abt.Types.Nat import Abt.Types.View import Abt.Class.HEq1 import Abt.Class.Show1 import Abt.Class.Abt import Abt.Class.Monad import Control.Applicative import Data.Profunctor import Data.Vinyl -- | A variable is a De Bruijn index, optionally decorated with a display name. data Var = Var { _varName ∷ !(Maybe String) , _varIndex ∷ !Int } instance Show Var where show (Var (Just v) _) = v show (Var Nothing i) = "@" ++ show i instance Eq Var where (Var _ i) == (Var _ j) = i == j instance Ord Var where compare (Var _ i) (Var _ j) = compare i j -- | A lens for '_varName'. -- -- @ -- 'varName' ∷ Lens' 'Var' ('Maybe' 'String') -- @ -- varName ∷ Functor f ⇒ (Maybe String → f (Maybe String)) → Var → f Var varName i (Var n j) = (\n' → Var n' j) <$> i n -- | A lens for '_varIndex'. -- -- @ -- 'varIndex' ∷ Lens' 'Var' 'Int' -- @ -- varIndex ∷ Functor f ⇒ (Int → f Int) → Var → f Var varIndex i (Var n j) = (\j' → Var n j') <$> i j -- | Locally nameless terms with operators in @o@ at order @n@. -- data Tm (o ∷ [Nat] → *) (n ∷ Nat) where Free ∷ Var → Tm0 o Bound ∷ Int → Tm0 o Abs ∷ Tm o n → Tm o (S n) App ∷ o ns → Rec (Tm o) ns → Tm0 o -- | First order terms (i.e. terms not headed by abstractions). -- type Tm0 o = Tm o Z instance HEq1 o ⇒ HEq1 (Tm o) where heq1 (Free v1) (Free v2) | v1 == v2 = Just Refl heq1 (Bound m) (Bound n) | m == n = Just Refl heq1 (Abs e1) (Abs e2) = cong <$> heq1 e1 e2 heq1 (App o1 es1) (App o2 es2) | Just Refl ← heq1 o1 o2 , Just Refl ← heq1 es1 es2 = Just Refl heq1 _ _ = Nothing shiftVar ∷ Var → Int → Tm o n → Tm o n shiftVar v n = \case Free v' → if v == v' then Bound n else Free v' Bound m → Bound m Abs e → Abs $ shiftVar v (n + 1) e App p es → App p $ shiftVar v n <<$>> es addVar ∷ Var → Int → Tm o n → Tm o n addVar v n = \case Free v' → Free v' Bound m → if m == n then Free v else Bound m Abs e → Abs $ addVar v (n + 1) e App p es → App p $ addVar v n <<$>> es instance Show1 o ⇒ Abt Var o (Tm o) where into = \case V v → Free v v :\ e → Abs $ shiftVar v 0 e v :$ es → App v es out = \case Free v → return $ V v Bound _ → fail "bound variable occured in out" Abs e → do v ← fresh return $ v :\ addVar v 0 e App p es → return $ p :$ es -- | A prism to extract arguments from a proposed operator. -- -- @ -- '_TmOp' ∷ 'HEq1' o ⇒ o ns → Prism' ('Tm0' o) ('Rec' ('Tm0' o) ns) -- @ -- _TmOp ∷ ( Choice p , Applicative f , HEq1 o ) ⇒ o ns → p (Rec (Tm o) ns) (f (Rec (Tm o) ns)) → p (Tm0 o) (f (Tm0 o)) _TmOp o = dimap fro (either pure (fmap (App o))) . right' where fro = \case App o' es | Just Refl ← heq1 o o' → Right es e → Left e