packages feed

caledon-0.0.0.0: AST.hs

{-# LANGUAGE  
 DeriveFunctor,
 FlexibleInstances,
 PatternGuards
 #-}
module AST where

import qualified Data.Foldable as F
import Data.List
import Data.Maybe
import Data.Monoid
import Data.Functor
import qualified Data.Map as M
import qualified Data.Set as S
--------------------------------------------------------------------
----------------------- DATA TYPES ---------------------------------
--------------------------------------------------------------------
type Name = String
              
data Variable = Var  Name
              | Cons Name
              deriving (Ord, Eq)
                       
data Tm = AbsImp Name Tp Tm
        | Abs Name Tp Tm
        | Spine Variable [Tp] 
        deriving (Eq, Ord)
                 
var nm = Spine (Var nm) []
cons nm = Spine (Cons nm) []

data Constraint a = a :=: a
                  deriving (Eq, Ord, Functor, Show)

data Tp = Atom Tm
        | Forall Name Tp Tp
        | ForallImp Name Tp Tp
        deriving (Eq, Ord)

data Predicate = Predicate { predName::Name
                           , predType::Tp 
                           , predConstructors::[(Name, Tp)]
                           } 
               | Query { predName :: Name, predType::Tp }
               deriving (Eq)

infixl 1 :|-
data Judgement = (:|-) { antecedent :: [(Name,Tp)] , succedent :: Tp }


atom = Atom $ cons "atom"


--------------------------------------------------------------------
----------------------- PRETTY PRINT -------------------------------
--------------------------------------------------------------------
instance Show Variable where
  show (Var n)  = n
  show (Cons n) = n
showWithParens t = if (case t of
                          Forall _ _ _ -> True
                          Atom (Spine _ lst) -> not $ null lst
                          Atom (Abs _ _ _) -> True
                          Atom (AbsImp _ _ _) -> True
                      ) then "("++show t++")" else show t 

instance Show Tm where
  show (Abs nm ty tm) = "λ "++nm++" : "++showWithParens ty++" . "++show tm
  show (AbsImp nm ty tm) = "?λ "++nm++" : "++showWithParens ty++" . "++show tm
  show (Spine cons apps) = show cons++concatMap (\s -> " "++showWithParens s) apps
instance Show Tp where
  show t = case t of
    Atom t -> show t
    Forall nm t t' | not (S.member nm (freeVariables t')) -> showWithParens++" → "++ show t'
      where showWithParens = case t of
              Forall _ _ _ -> "(" ++ show t ++ ")"
              _ ->  show t
    Forall nm ty t -> "∀ "++nm++" : "++show ty++" . "++show t
    
    ForallImp nm t t' | not (S.member nm (freeVariables t')) -> showWithParens++" ⇒ "++ show t'
      where showWithParens = case t of
              Forall _ _ _ -> "(" ++ show t ++ ")"
              _ ->  show t
    ForallImp nm ty t -> "?∀ "++nm++" : "++show ty++" . "++show t
  
instance Show Judgement where 
  show (a :|- b) =  removeHdTl (show a) ++" ⊢ "++ show b
    where removeHdTl = reverse . tail . reverse . tail    

instance Show Predicate where
  show (Predicate nm ty []) =  ""++"defn "++nm++" : "++show ty++";"
  show (Predicate nm ty (a:cons)) = 
      ""++"defn "++nm++" : "++show ty++"\n"
      ++  "  as "++showSingle a++concatMap (\x->
        "\n   | "++showSingle x) cons++";"
        where showSingle (nm,ty) = nm++" = "++show ty
  show (Query nm ty) = "query "++nm++" = "++show ty

--------------------------------------------------------------------
----------------------- SUBSTITUTION -------------------------------
--------------------------------------------------------------------
type Substitution = M.Map Name Tm

infixr 1 |->
infixr 0 ***
m1 *** m2 = M.union m2 (subst m2 <$> m1)
(|->) = M.singleton
(!) = flip M.lookup


rebuildSpine :: Tm -> [Tp] -> Tm
rebuildSpine s [] = s
rebuildSpine (Spine c apps) apps' = Spine c (apps ++ apps')
rebuildSpine (Abs nm _ rst) (a:apps') = rebuildSpine (subst (nm |-> tpToTm a) $ rst) apps'

newName nm s = (nm',s')
  where s' = if nm == nm' then s else M.insert nm (var nm') s 
        nm' = fromJust $ find free $ nm:map (\s -> show s ++ "/") [0..]
        fv = mappend (M.keysSet s) (freeVariables s)
        free k = not $ S.member k fv

class Subst a where
  subst :: Substitution -> a -> a
instance (Functor f , Subst a) => Subst (f a) where
  subst foo t = subst foo <$> t
instance Subst Tm where
  subst s (Abs nm t rst) = Abs nm' (subst s t) $ subst s' rst
    where (nm',s') = newName nm s
  subst s (AbsImp nm t rst) = AbsImp nm' (subst s t) $ subst s' rst
    where (nm',s') = newName nm s          
  subst s (Spine head apps) = let apps' = subst s <$> apps  in
    case head of
      Var nm | Just head' <- s ! nm -> rebuildSpine head' apps'
      _ -> Spine head apps'
instance Subst Tp where
  subst s t = case t of
    Atom t -> Atom $ subst s t
    ForallImp nm ty t -> ForallImp nm' (subst s ty) $ subst s' t  -- THIS RULE is unsafe capture!
        where (nm',s') = newName nm s
    Forall nm ty t -> Forall nm' (subst s ty) $ subst s' t  -- THIS RULE is unsafe capture!
        where (nm',s') = newName nm s
instance Subst Judgement where 
  subst foo (c :|- s) = subst foo c :|- subst foo s

--------------------------------------------------------------------
----------------------- FREE VARIABLES -----------------------------
--------------------------------------------------------------------
class FV a where         
  freeVariables :: a -> S.Set Name
  
instance (FV a, F.Foldable f) => FV (f a) where
  freeVariables m = F.foldMap freeVariables m
instance FV Tp where
  freeVariables t = case t of
    Forall a ty t -> (S.delete a $ freeVariables t) `S.union` (freeVariables ty)
    ForallImp a ty t -> (S.delete a $ freeVariables t) `S.union` (freeVariables ty)
    Atom a -> freeVariables a
instance FV Tm where
  freeVariables t = case t of
    Abs nm t p -> S.delete nm $ freeVariables p
    AbsImp nm t p -> S.delete nm $ freeVariables p    
    Spine head others -> mappend (freeVariables head) $ mconcat $ freeVariables <$> others
instance FV Variable where    
  freeVariables (Var a) = S.singleton a
  freeVariables _ = mempty
instance (FV a,FV b) => FV (a,b) where 
  freeVariables (a,b) = freeVariables a `S.union` freeVariables b
  
class ToTm t where
  tpToTm :: t -> Tm
instance ToTm Tp where
  tpToTm (Forall n ty t) = Spine (Cons "forall") [Atom $ Abs n ty $ tpToTm t ]
  tpToTm (ForallImp n ty t) = AbsImp n ty $ tpToTm t
  tpToTm (Atom tm) = tm