ddc-core-flow-0.4.1.1: DDC/Core/Flow/Transform/Thread.hs
-- | Definition for the thread transform.
module DDC.Core.Flow.Transform.Thread
( threadConfig
, wrapResultType
, wrapResultExp
, unwrapResult
, threadType)
where
import DDC.Core.Flow.Compounds
import DDC.Core.Flow.Profile
import DDC.Core.Flow.Prim
import DDC.Core.Compounds as C
import DDC.Core.Exp
import DDC.Core.Transform.Thread
import DDC.Core.Transform.Reannotate
import DDC.Core.Check (AnTEC (..))
import qualified DDC.Core.Check as Check
-- | Thread config defines what state token to use,
-- and what functions need to have it threaded though them.
threadConfig :: Config () Name
threadConfig
= Config
{ configCheckConfig = Check.configOfProfile profile
, configTokenType = tWorld
, configVoidType = tUnit
, configWrapResultType = wrapResultType
, configWrapResultExp = wrapResultExp
, configThreadMe = threadType
, configThreadPat = unwrapResult }
-- | Wrap the result type of a stateful computation with the state type.
wrapResultType :: Type Name -> Type Name
wrapResultType tt
| Just (TyConBound u _, tsArgs) <- takeTyConApps tt
, UPrim n _ <- u
, NameTyConFlow (TyConFlowTuple _) <- n
= tTupleN (tWorld : tsArgs)
| otherwise
= tTuple2 tWorld tt
-- | Wrap the result of a stateful computation with the state token.
wrapResultExp
:: Exp (AnTEC () Name) Name -- ^ World expression
-> Exp (AnTEC () Name) Name -- ^ Result expression
-> Exp () Name
wrapResultExp xWorld xResult
-- Rewrite Unit => World
| aResult <- annotOfExp xResult
, annotType aResult == tUnit
= reannotate annotTail xWorld
-- Rewrite (TupleN a1 a2 .. x1 x2 ..)
-- => (TupleN World# a1 a2 .. world x1 x2 ..)
| aWorld <- annotOfExp xWorld
, aResult <- annotOfExp xResult
= let tWorld' = annotType aWorld
tResult = annotType aResult
xWorld' = reannotate annotTail xWorld
xResult' = reannotate annotTail xResult
in case C.takeXConApps xResult' of
Just (dc, xa)
| DaConPrim (NameDaConFlow (DaConFlowTuple n)) _ <- dc
, x <- length xa
, x >= 2
-> let (b, a) = splitAt (x `quot` 2) xa
in C.xApps () (XCon () (dcTupleN $ n + 1))
$ XType (annotTail aWorld) tWorld' : b -- World# : a1 a2 ..
++ xWorld' : a -- world : x1 x2 ..
_ -> C.xApps () (XCon () (dcTupleN 2))
[ XType (annotTail aWorld) tWorld'
, XType (annotTail aResult) tResult
, xWorld'
, xResult' ]
| otherwise
= error "ddc-core-flow: wrapResultExp can't get type annotations"
-- | Make a pattern to unwrap the result of a stateful computation.
unwrapResult :: Name -> Maybe (Bind Name -> [Bind Name] -> Pat Name)
unwrapResult _
= Just unwrap
where unwrap bWorld bsResult
| [bResult] <- bsResult
, typeOfBind bResult == tUnit
= PData dcTuple1 [bWorld]
| otherwise
= PData (dcTupleN (length (bWorld : bsResult)))
(bWorld : bsResult)
-- | Get the new type for a stateful primop.
-- The new types have a World# token threaded though them, which make them
-- suitable for applying the Thread transform when converting a Core Flow
-- program to a language that needs such state threading (like GHC Core).
threadType :: Name -> Type Name -> Maybe (Type Name)
threadType n _
= case n of
-- Assignables --------------------------
-- new# :: [a : Data]. a -> World# -> T2# (World#, Ref# a)
NameOpStore OpStoreNew
-> Just $ tForall kData
$ \tA -> tA
`tFun` tWorld `tFun` (tTuple2 tWorld (tRef tA))
-- read# :: [a : Data]. Ref# a -> World# -> T2# (World#, a)
NameOpStore OpStoreRead
-> Just $ tForall kData
$ \tA -> tRef tA
`tFun` tWorld `tFun` (tTuple2 tWorld (tRef tA))
-- write# :: [a : Data]. Ref# -> a -> World# -> World#
NameOpStore OpStoreWrite
-> Just $ tForall kData
$ \tA -> tRef tA `tFun` tA
`tFun` tWorld `tFun` tWorld
-- Vectors -------------------------------
-- vnew# :: [a : Data]. Nat# -> World# -> T2# World# (Vector# a)
NameOpStore OpStoreNewVector
-> Just $ tForall kData
$ \tA -> tNat
`tFun` tWorld `tFun` (tTuple2 tWorld (tVector tA))
-- vnew# :: [a : Data]. [k : Rate]. RateNat# k
-- -> World# -> T2# (World#, Vector# a)
NameOpStore OpStoreNewVectorN
-> Just $ tForalls [kData, kRate]
$ \[tA, tK]
-> tRateNat tK
`tFun` tWorld `tFun` (tTuple2 tWorld (tVector tA))
-- vread# :: [a : Data]. Vector# a -> Nat# -> World# -> T2# World# a
NameOpStore (OpStoreReadVector _)
-> Just $ tForall kData
$ \tA -> tA `tFun` tVector tA `tFun` tNat
`tFun` tWorld `tFun` (tTuple2 tWorld tA)
-- vwrite# :: [a : Data]. Vector# a -> Nat# -> a -> World# -> World#
NameOpStore (OpStoreWriteVector _)
-> Just $ tForall kData
$ \tA -> tA `tFun` tVector tA `tFun` tNat `tFun` tA
`tFun` tWorld `tFun` tWorld
-- vtrunc# :: [a : Data]. Nat# -> Vector# a -> World# -> World#
NameOpStore OpStoreTruncVector
-> Just $ tForall kData
$ \tA -> tNat `tFun` tVector tA
`tFun` tWorld `tFun` tWorld
-- Series ------------------------------
-- next# :: [k : Rate]. [a : Data]
-- . Series# k a -> Int# -> World# -> (World#, a)
NameOpConcrete (OpConcreteNext 1)
-> Just $ tForalls [kRate, kData]
$ \[tK, tA] -> tSeries tK tA `tFun` tInt
`tFun` tWorld `tFun` (tTuple2 tWorld tA)
-- nextN# :: [k : Rate]. [a : Data]
-- . Series# k a -> Int# -> World# -> (World#, a)
NameOpConcrete (OpConcreteNext c)
| c >= 2
-> Just $ tForalls [kRate, kData]
$ \[tK, tA] -> tSeries (tDown c tK) tA `tFun` tInt
`tFun` tWorld `tFun` (tTuple2 tWorld (tVec c tA))
-- Control -----------------------------
-- loopn# :: [k : Rate]. RateNat# k
-- -> (Nat# -> World# -> World#)
-- -> World# -> World#
NameOpControl OpControlLoopN
-> Just $ tForalls [kRate]
$ \[tK] -> tRateNat tK
`tFun` (tNat `tFun` tWorld `tFun` tWorld)
`tFun` tWorld `tFun` tWorld
-- guard#
NameOpControl OpControlGuard
-> Just $ tRef tNat
`tFun` tBool
`tFun` (tNat `tFun` tWorld `tFun` tWorld)
`tFun` tWorld `tFun` tWorld
-- split# :: [k : Rate]. RateNat# k
-- -> (RateNat# (Down8# k) -> World# -> World#)
-- -> (RateNat# (Tail8# k) -> World# -> World#)
-- -> World# -> World#
NameOpControl (OpControlSplit c)
-> Just $ tForall kRate
$ \tK -> tRateNat tK
`tFun` (tRateNat (tDown c tK) `tFun` tWorld `tFun` tWorld)
`tFun` (tRateNat (tTail c tK) `tFun` tWorld `tFun` tWorld)
`tFun` tWorld `tFun` tWorld
_ -> Nothing