co-feldspar-0.1.0.1: src/Feldspar/Software/Expression.hs
{-# language GADTs #-}
{-# language StandaloneDeriving #-}
{-# language TypeOperators #-}
{-# language FlexibleInstances #-}
{-# language FlexibleContexts #-}
{-# language UndecidableInstances #-}
{-# language MultiParamTypeClasses #-}
{-# language ConstraintKinds #-}
{-# language TypeFamilies #-}
{-# options_ghc -fwarn-incomplete-patterns #-}
module Feldspar.Software.Expression where
import Feldspar.Sugar
import Feldspar.Representation
import Feldspar.Software.Primitive
import Data.Struct
import Data.Complex (Complex)
import Data.Int
import Data.Word
import Data.List (genericTake)
import Data.Constraint
import Data.Typeable (Typeable)
-- syntactic.
import Language.Syntactic hiding (Signature, Args)
import Language.Syntactic.Functional hiding (Lam)
import Language.Syntactic.Functional.Tuple
import qualified Language.Syntactic as Syn
-- imperative-edsl.
import Language.Embedded.Expression
--------------------------------------------------------------------------------
-- * Software expressions.
--------------------------------------------------------------------------------
type instance Pred SoftwareDomain = SoftwarePrimType
--------------------------------------------------------------------------------
-- hmm...
type instance ExprOf (SExp a) = SExp
type instance PredOf SExp = SoftwarePrimType
type instance DomainOf SExp = SoftwareDomain
type instance RepresentationOf SoftwarePrimType = SoftwarePrimTypeRep
--------------------------------------------------------------------------------
-- ** Software types.
-- | Representation of supported software types.
type STypeRep = TypeRep SoftwarePrimType SoftwarePrimTypeRep
-- | ...
type STypeRepF = TypeRepF SoftwarePrimType SoftwarePrimTypeRep
instance Type SoftwarePrimType Bool where typeRep = Node BoolST
instance Type SoftwarePrimType Int8 where typeRep = Node Int8ST
instance Type SoftwarePrimType Int16 where typeRep = Node Int16ST
instance Type SoftwarePrimType Int32 where typeRep = Node Int32ST
instance Type SoftwarePrimType Int64 where typeRep = Node Int64ST
instance Type SoftwarePrimType Word8 where typeRep = Node Word8ST
instance Type SoftwarePrimType Word16 where typeRep = Node Word16ST
instance Type SoftwarePrimType Word32 where typeRep = Node Word32ST
instance Type SoftwarePrimType Word64 where typeRep = Node Word64ST
instance Type SoftwarePrimType Float where typeRep = Node FloatST
instance Type SoftwarePrimType Double where typeRep = Node DoubleST
instance Type SoftwarePrimType (Complex Float) where typeRep = Node ComplexFloatST
instance Type SoftwarePrimType (Complex Double) where typeRep = Node ComplexDoubleST
-- | Compare two software types for equality.
softwareTypeEq :: STypeRep a -> STypeRep b -> Maybe (Dict (a ~ b))
softwareTypeEq (Node t) (Node u) = softwarePrimTypeEq t u
softwareTypeEq (Branch t1 u1) (Branch t2 u2) = do
Dict <- softwareTypeEq t1 t2
Dict <- softwareTypeEq u1 u2
return Dict
softwareTypeEq _ _ = Nothing
-- | Construct the software type representation of 'a'.
softwareTypeRep :: Struct SoftwarePrimType c a -> STypeRep a
softwareTypeRep = mapStruct (const softwareRep)
--------------------------------------------------------------------------------
-- | Short-hand for software types.
type SType = Type SoftwarePrimType
-- | Short-hand for primitive software types.
type SType' = PrimType SoftwarePrimType
--------------------------------------------------------------------------------
-- ** Software expression symbols.
data AssertionLabel =
-- ^ Internal assertion to guarantee meaningful results.
InternalAssertion
-- ^ User made assertion.
| UserAssertion String
deriving (Eq, Show)
-- | Guard a value with an assertion.
data GuardVal sig
where
GuardVal :: AssertionLabel -> String -> GuardVal (Bool :-> a :-> Full a)
deriving instance Eq (GuardVal a)
deriving instance Show (GuardVal a)
deriving instance Typeable (GuardVal a)
--------------------------------------------------------------------------------
-- | Hint that a value may appear in an invariant
data HintVal sig
where
HintVal :: SoftwarePrimType a => HintVal (a :-> b :-> Full b)
deriving instance Eq (HintVal a)
deriving instance Show (HintVal a)
deriving instance Typeable (HintVal a)
--------------------------------------------------------------------------------
-- | For loop.
data ForLoop sig
where
ForLoop :: SType st =>
ForLoop (Length :-> Length :-> st :-> (Index -> st -> st) :-> Full st)
deriving instance Eq (ForLoop a)
deriving instance Show (ForLoop a)
deriving instance Typeable (ForLoop a)
--------------------------------------------------------------------------------
{-
-- |
data Foreign sig
where
Foreign :: Signature sig => String -> Denotation sig -> Foreign sig
-}
--------------------------------------------------------------------------------
-- | Software symbols.
type SoftwareConstructs =
BindingT
Syn.:+: Let
Syn.:+: Tuple
Syn.:+: SoftwarePrimConstructs
Syn.:+: Construct
-- ^ Software specific symbol.
Syn.:+: GuardVal
Syn.:+: HintVal
Syn.:+: ForLoop
-- | Software symbols tagged with their type representation.
type SoftwareDomain = SoftwareConstructs :&: TypeRepF SoftwarePrimType SoftwarePrimTypeRep
-- | Software expressions.
newtype SExp a = SExp { unSExp :: ASTF SoftwareDomain a }
-- | Evaluate a closed software expression.
eval :: (Syntactic a, Domain a ~ SoftwareDomain) => a -> Internal a
eval = evalClosed . desugar
-- | Sugar a software symbol as a smart constructor.
sugarSymSoftware
:: ( Syn.Signature sig
, fi ~ SmartFun dom sig
, sig ~ SmartSig fi
, dom ~ SmartSym fi
, dom ~ SoftwareDomain
, SyntacticN f fi
, sub :<: SoftwareConstructs
, Type SoftwarePrimType (DenResult sig)
)
=> sub sig -> f
sugarSymSoftware = sugarSymDecor $ ValT $ typeRep
-- | Sugar a software symbol as a primitive smart constructor.
sugarSymPrimSoftware
:: ( Syn.Signature sig
, fi ~ SmartFun dom sig
, sig ~ SmartSig fi
, dom ~ SmartSym fi
, dom ~ SoftwareDomain
, SyntacticN f fi
, sub :<: SoftwareConstructs
, SoftwarePrimType (DenResult sig)
)
=> sub sig -> f
sugarSymPrimSoftware = sugarSymDecor $ ValT $ Node softwareRep
--------------------------------------------------------------------------------
instance Syntactic (SExp a)
where
type Domain (SExp a) = SoftwareDomain
type Internal (SExp a) = a
desugar = unSExp
sugar = SExp
instance Syntactic (Struct SoftwarePrimType SExp a)
where
type Domain (Struct SoftwarePrimType SExp a) = SoftwareDomain
type Internal (Struct SoftwarePrimType SExp a) = a
desugar (Node a) = unSExp a
desugar (Branch a b) = sugarSymDecor (ValT $ Branch ta tb) Pair a' b'
where
a' = desugar a
b' = desugar b
ValT ta = getDecor a'
ValT tb = getDecor b'
sugar a = case getDecor a of
ValT (Node _) -> Node $ SExp a
ValT (Branch ta tb) -> Branch
(sugarSymDecor (ValT ta) Fst a)
(sugarSymDecor (ValT tb) Snd a)
FunT _ _ -> error "Syntactic can't sugar a function."
instance Tuples SoftwareDomain
where
pair = sugarSymSoftware Pair
first = sugarSymSoftware Fst
second = sugarSymSoftware Snd
instance FreeExp SExp
where
type FreePred SExp = PrimType SoftwarePrimType
constExp = sugarSymSoftware . Lit
varExp = sugarSymSoftware . FreeVar
--------------------------------------------------------------------------------
-- syntactic instances.
instance Eval GuardVal
where
evalSym (GuardVal InternalAssertion msg) = \cond a ->
if cond then a else error $ "Internal assertion failure: " ++ show msg
evalSym (GuardVal (UserAssertion ass) msg) = \cond a ->
if cond then a else error $ "User assertion " ++ show ass ++ " failure: " ++ show msg
instance Symbol GuardVal
where
symSig (GuardVal _ _) = signature
instance Render GuardVal
where
renderSym = show
renderArgs = renderArgsSmart
instance EvalEnv GuardVal env
instance StringTree GuardVal
instance Equality GuardVal
--------------------------------------------------------------------------------
instance Eval HintVal
where
evalSym (HintVal) = flip const
instance Symbol HintVal
where
symSig (HintVal) = signature
instance Render HintVal
where
renderSym = show
renderArgs = renderArgsSmart
instance EvalEnv HintVal env
instance StringTree HintVal
instance Equality HintVal
--------------------------------------------------------------------------------
instance Eval ForLoop
where
evalSym ForLoop = \min max init body ->
foldl (flip body) init [min..max]
instance Symbol ForLoop
where
symSig (ForLoop) = signature
instance Render ForLoop
where
renderSym = show
renderArgs = renderArgsSmart
instance EvalEnv ForLoop env
instance StringTree ForLoop
instance Equality ForLoop
--------------------------------------------------------------------------------
-- *** Temporary fix until GHC fixes their class resolution for DTC ***
instance {-# OVERLAPPING #-} Project sub SoftwareConstructs =>
Project sub (AST SoftwareDomain)
where
prj (Sym s) = Syn.prj s
prj _ = Nothing
instance {-# OVERLAPPING #-} Project sub SoftwareConstructs =>
Project sub SoftwareDomain
where
prj (expr :&: info) = Syn.prj expr
instance {-# OVERLAPPING #-} Project BindingT SoftwareConstructs
where
prj (InjL a) = Just a
prj _ = Nothing
instance {-# OVERLAPPING #-} Project Let SoftwareConstructs
where
prj (InjR (InjL a)) = Just a
prj _ = Nothing
instance {-# OVERLAPPING #-} Project Tuple SoftwareConstructs
where
prj (InjR (InjR (InjL a))) = Just a
prj _ = Nothing
instance {-# OVERLAPPING #-} Project SoftwarePrimConstructs SoftwareConstructs
where
prj (InjR (InjR (InjR (InjL a)))) = Just a
prj _ = Nothing
instance {-# OVERLAPPING #-} Project Construct SoftwareConstructs
where
prj (InjR (InjR (InjR (InjR (InjL a))))) = Just a
prj _ = Nothing
instance {-# OVERLAPPING #-} Project GuardVal SoftwareConstructs
where
prj (InjR (InjR (InjR (InjR (InjR (InjL a)))))) = Just a
prj _ = Nothing
instance {-# OVERLAPPING #-} Project HintVal SoftwareConstructs
where
prj (InjR (InjR (InjR (InjR (InjR (InjR (InjL a))))))) = Just a
prj _ = Nothing
instance {-# OVERLAPPING #-} Project ForLoop SoftwareConstructs
where
prj (InjR (InjR (InjR (InjR (InjR (InjR (InjR a))))))) = Just a
prj _ = Nothing
--------------------------------------------------------------------------------