ddc-core-flow-0.3.2.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
| Just aResult <- takeAnnotOfExp xResult
, annotType aResult == tUnit
= reannotate annotTail xWorld
-- Rewrite (TupleN a1 a2 .. x1 x2 ..)
-- => (TupleN World# a1 a2 .. world x1 x2 ..)
| Just aWorld <- takeAnnotOfExp xWorld
, Just aResult <- takeAnnotOfExp xResult
= let tWorld' = annotType aWorld
tResult = annotType aResult
xWorld' = reannotate annotTail xWorld
xResult' = reannotate annotTail xResult
in
-- ISSUE #308: Handle Tuple arities generically in thread transform.
case C.takeXConApps xResult' of
Just (dc, [xT1, xT2
, x1, x2])
| dc == dcTupleN 2
-> C.xApps () (XCon () (dcTupleN 3))
[ XType tWorld', xT1, xT2
, xWorld', x1, x2]
Just (dc, [xT1, xT2, xT3
, x1, x2, x3])
| dc == dcTupleN 3
-> C.xApps () (XCon () (dcTupleN 4))
[ XType tWorld', xT1, xT2, xT3
, xWorld', x1, x2, x3]
Just (dc, [xT1, xT2, xT3, xT4
, x1, x2, x3, x4])
| dc == dcTupleN 4
-> C.xApps () (XCon () (dcTupleN 5))
[ XType tWorld', xT1, xT2, xT3, xT4
, xWorld', x1, x2, x3, x4]
_ -> C.xApps () (XCon () (dcTupleN 2))
[ XType tWorld'
, XType 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 -------------------------------
-- newVector# :: [a : Data]. Nat# -> World# -> T2# World# (Vector# a)
NameOpStore OpStoreNewVector
-> Just $ tForall kData
$ \tA -> tNat
`tFun` tWorld `tFun` (tTuple2 tWorld (tVector tA))
-- newVectorN# :: [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))
-- readVector# :: [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)
-- writeVector# :: [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
-- sliceVector# :: [a : Data]. Nat# -> Vector# a -> World# -> T2# World# (Vector# a)
NameOpStore OpStoreSliceVector
-> Just $ tForall kData
$ \tA -> tNat `tFun` tVector tA
`tFun` tWorld `tFun` (tTuple2 tWorld (tVector tA))
-- Streams ------------------------------
-- next# :: [k : Rate]. [a : Data]
-- . Series# k a -> Int# -> World# -> (World#, a)
NameOpStore OpStoreNext
-> Just $ tForalls [kRate, kData]
$ \[tK, tA] -> tSeries tK tA `tFun` tInt
`tFun` tWorld `tFun` (tTuple2 tWorld tA)
-- Contexts -----------------------------
-- loopn# :: [k : Rate]. RateNat# k
-- -> (Nat# -> World# -> World#)
-- -> World# -> World#
NameOpLoop OpLoopLoopN
-> Just $ tForalls [kRate]
$ \[tK] -> tRateNat tK
`tFun` (tNat `tFun` tWorld `tFun` tWorld)
`tFun` tWorld `tFun` tWorld
-- guard#
NameOpLoop OpLoopGuard
-> Just $ tRef tNat
`tFun` tBool
`tFun` (tNat `tFun` tWorld `tFun` tWorld)
`tFun` tWorld `tFun` tWorld
_ -> Nothing