co-feldspar-0.1.0.1: src/Feldspar/Verify/FirstOrder.hs
{-# language DataKinds #-}
{-# language GADTs #-}
{-# language TypeFamilies #-}
{-# language MultiParamTypeClasses #-}
{-# language PolyKinds #-}
{-# language DefaultSignatures #-}
{-# language FlexibleInstances #-}
{-# language TypeOperators #-}
{-# language RankNTypes #-}
{-# language FlexibleContexts #-}
{-# language ConstraintKinds #-}
module Feldspar.Verify.FirstOrder where
import Control.Monad.Identity
import Control.Monad.State
import Control.Monad.Trans
import Control.Monad.Operational.Higher
import Data.Constraint
import Data.Maybe (fromMaybe)
import Data.Typeable
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
--------------------------------------------------------------------------------
-- * First-order representation of programs.
--------------------------------------------------------------------------------
-- | First-Order representation of programs, as a sequence of instructions.
data Sequence instr fs a
where
Val :: a -> Sequence instr fs a
Seq :: b -- Binder.
-> instr '(Sequence instr fs, fs) b -- Value.
-> Sequence instr fs a
-> Sequence instr fs a
deriving Typeable
--------------------------------------------------------------------------------
data HO instr fs a
where
Skip :: HO instr fs ()
Unnamed :: instr fs a -> HO instr fs a
Named :: (Ex a, Typeable a) => instr fs a -> HO instr fs a
class Defunctionalise inv instr
where
type FO inv instr :: (* -> *, (* -> *, (* -> Constraint, *))) -> * -> *
type FO inv instr = instr
defunc :: Fresh m => inv -> instr fs a -> m (FO inv instr fs a)
default defunc :: (FO inv instr ~ instr, Fresh m) =>
inv -> instr fs a -> m (FO inv instr fs a)
defunc _ = return
refunc :: (Defunctionalise inv jnstr, Sub exp pred, pred Bool) => inv -> Subst ->
FO inv instr (Param3 (Sequence (FO inv jnstr) (Param2 exp pred)) exp pred) a ->
HO instr (Param3 (Program jnstr (Param2 exp pred)) exp pred) a
instance (Defunctionalise inv instr, Defunctionalise inv jnstr) =>
Defunctionalise inv (instr :+: jnstr)
where
type FO inv (instr :+: jnstr) = FO inv instr :+: FO inv jnstr
defunc inv (Inl instr) = fmap Inl $ defunc inv instr
defunc inv (Inr jnstr) = fmap Inr $ defunc inv jnstr
refunc inv sub (Inl instr) = case refunc inv sub instr of
Named i -> Named $ Inl i
Unnamed i -> Unnamed $ Inl i
Skip -> Skip
refunc inv sub (Inr jnstr) = case refunc inv sub jnstr of
Named j -> Named $ Inr j
Unnamed j -> Unnamed $ Inr j
Skip -> Skip
--------------------------------------------------------------------------------
defunctionalise ::
( HFunctor instr
, Symbol instr
, Defunctionalise inv instr
, HTraversable (FO inv instr)
) =>
inv -> Program instr fs a -> Sequence (FO inv instr) fs a
defunctionalise inv prg = evalState (defunctionaliseM inv prg) (0 :: Integer)
defunctionaliseM ::
( Monad m
, Fresh m
, HFunctor instr
, Symbol instr
, Defunctionalise inv instr
, HTraversable (FO inv instr)
) =>
inv -> Program instr fs a -> m (Sequence (FO inv instr) fs a)
defunctionaliseM inv prg = case view prg of
Return val -> return (Val val)
(:>>=) instr f -> do
binder <- dry instr
instr' <- defunc inv instr
fonstr <- htraverse (defunctionaliseM inv) instr'
tail <- defunctionaliseM inv (f binder)
return (Seq binder fonstr tail)
--------------------------------------------------------------------------------
refunctionalise :: (Defunctionalise inv instr, Sub exp pred, pred Bool) =>
inv ->
Sequence (FO inv instr) (Param2 exp pred) a ->
Program instr (Param2 exp pred) a
refunctionalise inv = refunctionaliseM inv Map.empty
refunctionaliseM :: (Defunctionalise inv instr, Sub exp pred, pred Bool) =>
inv ->
Subst ->
Sequence (FO inv instr) (Param2 exp pred) a ->
Program instr (Param2 exp pred) a
refunctionaliseM _ _ (Val val) = return val
refunctionaliseM inv sub (Seq n fo tail) =
case refunc inv sub fo of
Unnamed instr -> do
singleton instr
refunctionaliseM inv sub tail
Named instr -> do
new <- singleton instr
refunctionaliseM inv (extendSubst n new sub) tail
Skip -> do
refunctionaliseM inv sub tail
--------------------------------------------------------------------------------
class HFunctor instr => HTraversable instr
where
htraverse :: Applicative f
=> (forall b . prog1 b -> f (prog2 b))
-> instr '(prog1, fs) a
-> f (instr '(prog2, fs) a)
htraverse _ i = pure (hfmap (\_ -> error "traverse compound instruction") i)
instance (HTraversable f, HTraversable g) => HTraversable (f :+: g)
where
htraverse f (Inl x) = fmap Inl (htraverse f x)
htraverse f (Inr x) = fmap Inr (htraverse f x)
--------------------------------------------------------------------------------
class Monad m => Fresh m
where
fresh :: m Integer
default fresh :: (m ~ t n, MonadTrans t, Fresh n) => m Integer
fresh = lift fresh
instance Monad m => Fresh (StateT Integer m)
where
fresh = do i <- get; put (i + 1); return i
freshStr :: Fresh m => String -> m String
freshStr base = do i <- fresh; return (base ++ show i)
--------------------------------------------------------------------------------
class Symbol instr
where
dry :: Fresh m => instr fs a -> m a
instance (Symbol instr, Symbol jnstr) => Symbol (instr :+: jnstr)
where
dry (Inl instr) = dry instr
dry (Inr jnstr) = dry jnstr
--------------------------------------------------------------------------------
class Name a
where
name :: a -> String
data E
where
E :: (Typeable a, Name a) => a -> E
instance Eq E
where
x == y = compare x y == EQ
instance Ord E
where
compare (E a) (E b) = compare (name a) (name b) `mappend`
compare (typeOf a) (typeOf b)
class Ex a
where
hide :: Typeable a => a -> E
--------------------------------------------------------------------------------
type Subst = Map E E
class Substitute exp
where
type SubstPred exp :: * -> Constraint
subst :: SubstPred exp a => Subst -> exp a -> exp a
class TypeablePred pred
where
witnessTypeable :: Dict (pred a) -> Dict (Typeable a)
type Sub exp pred = (Substitute exp, SubstPred exp ~ pred, TypeablePred pred)
extendSubst :: (Ex a, Typeable a) => a -> a -> Subst -> Subst
extendSubst x y = Map.insert (hide x) (hide y)
lookupSubst :: (Ex a, Typeable a) => Subst -> a -> a
lookupSubst sub x = fromMaybe x $ case Map.lookup (hide x) sub of
Just (E y) -> cast y
Nothing -> Nothing
--------------------------------------------------------------------------------