packages feed

pisigma-0.1.0.2: src/PiSigma/Nf.hs

{-# LANGUAGE UndecidableInstances, MultiParamTypeClasses, FunctionalDependencies,
             TypeSynonymInstances, FlexibleInstances #-}
module PiSigma.Nf where

{- Implementation of a normalisation function.
   Useful for testing.
-}

import Control.Monad

import PiSigma.Syntax
import PiSigma.Evaluation

type Vars = [String]

fresh :: Name -> Vars -> Name
fresh x xs = if x/="" && elem x xs then fresh (x++"'") xs
             else x

class Nf a b | a -> b where
    nf :: Env e => Vars -> a -> Eval e b
    nf = nf' True
    quote :: Env e => Vars -> a -> Eval e b
    quote = nf' False
    nf' :: Env e => Bool -> Vars -> a -> Eval e b


instance Nf (Clos Term) Term where
    nf' True xs t = do t' <- eval t
                       nf' True xs t'
    nf' False xs t = qq xs t

instance Nf Id Term where
    nf' b xs i = do e <- getEnv
                    let (PrtInfo x exp) = prtE e i
                    case getE e i of
                      (Id _) -> return (Var x) 
                      (Closure t) -> if exp then nf' b xs t
                                     -- this is bad, we should not
                                     -- expand inside a box!
                                     else return (Var x) 

qq :: Env e => Vars -> Clos Term -> Eval e Term
qq xs (Var x,s) = do i <- getId x s
                     quote xs i
qq xs (Let g t, s) = fail "quote let: not implemented!"
{-do s' <- evalProg (g,s)
                        qq xs (t,s')  
                       -- this seems wrong! we should return a Let
                       -- and we should extend xs!
-}
qq xs (Q ps (a,(x,b)),s) = 
    do a' <- qq xs (a,s)
       xb' <- quote xs (x,(b,s))
       return (Q ps (a',xb'))
qq xs (Lift t,s) = liftM Lift (qq xs (t,s))
qq xs (Lam (x,t), s) = liftM Lam (quote xs (x,(t,s)))
qq xs (t :. u ,s) = do t' <- qq xs (t,s)
                       u' <- qq xs (u,s)
                       return (t' :. u')
qq xs (Pair (t,u),s) = do t' <- qq xs (t,s)
                          u' <- qq xs (u,s)
                          return (Pair (t',u'))
qq xs (Split t (x,(y,u)),s) = do t' <- qq xs (t,s)
                                 xyu' <- quote xs (x,(y,(u,s)))
                                 return (Split t' xyu')
qq xs (Case t lts,s) = do t' <- qq xs (t,s)
                          lts' <- mapM (\ (l,t) -> 
                                            do t' <- qq xs (t,s)
                                               return (l,t')) lts
                          return (Case t' lts')              
qq xs (Box t,s) = liftM Box (qq xs (t,s))
qq xs (Force t,s) = liftM Force (qq xs (t,s))
qq xs (t,s) = return t -- Type, Enum, Label

instance (Closure a,Nf a b) => Nf (Bind a) (Bind b) where
    nf' b xs (x,t)  = do let x' = fresh x xs
                         (i,s') <- decl x (PrtInfo x' True) (getScope t) Nothing
                         t' <- nf' b (x':xs) (putScope t s')
                         return (x',t')

instance Nf Val Term where
    nf' b xs (Ne n) = nf' b xs n
    nf' b xs VType = return Type
    nf' b xs (VQ ps ((a,(x,c)),s)) = do a' <- nf' b xs (a,s) 
                                        xc' <- nf' b xs (x,(c,s))
                                        return (Q ps (a',xc'))
    nf' b xs (VLift c) = liftM Lift (nf' b xs c)
    nf' b xs (VLam xt) = liftM Lam (nf' b xs xt)
    nf' b xs (VPair ((t,u),s)) = do t' <- nf' b xs (t,s)
                                    u' <- nf' b xs (u,s)
                                    return (Pair (t',u'))
    nf' b xs (VBox (Boxed c)) = liftM Box (nf' False xs c)
    nf' b xs (VEnum ls) = return (Enum ls)
    nf' b xs (VLabel l) = return (Label l)


instance Nf Ne Term where
    nf' b xs (NVar i) = nf' b xs i
    nf' b xs (t' :.. u) = do t <- nf' b xs t'
                             u' <- nf' b xs u
                             return (t :. u')
    nf' b xs (NSplit t xyu) = do t' <- nf' b xs t
                                 xyu' <- nf' b xs xyu
                                 return (Split t' xyu')
    nf' b xs (NCase t (lus,s)) = do t' <- nf xs t
                                    lus' <- mapM (\ (l,u) -> 
                                                   do u' <- nf' b xs (u,s)
                                                      return (l,u')) lus
                                    return (Case t' lus')
    nf' b xs (NForce t) = liftM Force (nf xs t)