Church implemented.

This commit is contained in:
Alexander Granin 2019-05-09 14:26:54 +07:00
parent 1aca0400e9
commit dd51164b61
27 changed files with 243 additions and 98 deletions

View File

@ -9,7 +9,7 @@ import qualified Data.Map as Map
import qualified Data.Set as Set
import Hydra.Prelude
import qualified Hydra.Church as L
import qualified Hydra.ChurchL as L
import qualified Hydra.Domain as D
import qualified Hydra.Runtime as R
import Types

View File

@ -11,6 +11,7 @@ import Hydra.Prelude
import qualified Free as Free
import qualified FTL as FTL
import qualified Church as Church
import qualified Hydra.Domain as D
import qualified Hydra.Runtime as R
@ -59,3 +60,8 @@ main = do
when (scenario1 cfg) $ Free.scenario1 ops coreRt
when (scenario2 cfg) $ Free.scenario2 ops coreRt
when (scenario3 cfg) $ Free.scenario3 ops coreRt
when (method cfg == ChurchM) $ do
when (scenario1 cfg) $ Church.scenario1 ops coreRt
when (scenario2 cfg) $ Church.scenario2 ops coreRt
when (scenario3 cfg) $ Church.scenario3 ops coreRt

4
cfg
View File

@ -1,8 +1,8 @@
Config
{ useLog = False
, method = FreeM
, method = FT
, iterations = 1000000
, scenario1 = True
, scenario2 = False
, scenario3 = False
}
}

View File

@ -6,5 +6,5 @@ import Hydra.Core.ControlFlow.ChurchI as X
import Hydra.Core.Lang.ChurchI as X
-- -- import Hydra.Core.Logger.ChurchI as X
-- import Hydra.Core.Process.ChurchI as X
-- import Hydra.Core.Random.ChurchI as X
import Hydra.Core.Random.ChurchI as X
-- import Hydra.Core.State.ChurchI as X

View File

@ -3,8 +3,11 @@ module Hydra.Core.ChurchL
) where
import Hydra.Core.ControlFlow.ChurchL as X
import Hydra.Core.ControlFlow.Class as X
import Hydra.Core.Lang.ChurchL as X
-- import Hydra.Core.Logger.ChurchL as X
import Hydra.Core.Logger.ChurchL as X
import Hydra.Core.Logger.Class as X
-- import Hydra.Core.Process.ChurchL as X
-- import Hydra.Core.Random.ChurchL as X
import Hydra.Core.Random.ChurchL as X
import Hydra.Core.Random.Class as X
-- import Hydra.Core.State.ChurchL as X

View File

@ -3,6 +3,7 @@ module Hydra.Core.ControlFlow.ChurchL where
import Hydra.Prelude
import qualified Hydra.Core.ControlFlow.Language as L
import qualified Hydra.Core.ControlFlow.Class as L
type ControlFlowL = F L.ControlFlowF

View File

@ -0,0 +1,6 @@
module Hydra.Core.ControlFlow.Class where
import Hydra.Prelude
class ControlFlow m where
delay :: Int -> m ()

View File

@ -2,6 +2,8 @@ module Hydra.Core.ControlFlow.Language where
import Hydra.Prelude
import Hydra.Core.ControlFlow.Class
data ControlFlowF next where
-- | Freeze the current thread on time (in microseconds).
Delay :: Int -> (() -> next) -> ControlFlowF next
@ -11,8 +13,5 @@ instance Functor ControlFlowF where
type ControlFlowL = Free ControlFlowF
class ControlFlow m where
delay :: Int -> m ()
instance ControlFlow (Free ControlFlowF) where
delay i = liftF $ Delay i id

View File

@ -3,6 +3,8 @@ module Hydra.Core.Lang.ChurchI where
import Hydra.Prelude
import Hydra.Core.ControlFlow.ChurchI (runControlFlowL)
import Hydra.Core.Random.ChurchI (runRandomL)
import Hydra.Core.Logger.Impl.HsLoggerChurchI (runLoggerL)
import qualified Hydra.Core.Lang.ChurchL as CL
import qualified Hydra.Core.Lang.Interpreter as I
import qualified Hydra.Core.Lang.Language as L
@ -10,17 +12,17 @@ import qualified Hydra.Core.RLens as RLens
import qualified Hydra.Core.Runtime as R
-- | Interprets core lang.
interpretLangF :: R.CoreRuntime -> L.LangF a -> IO a
interpretLangF :: R.CoreRuntime -> CL.LangF a -> IO a
-- interpretLangF coreRt (L.EvalStateAtomically action next) = do
-- let stateRt = coreRt ^. RLens.stateRuntime
-- let loggerRt = coreRt ^. RLens.loggerRuntime
-- res <- atomically $ runStateL stateRt action
-- R.flushStmLogger stateRt loggerRt
-- pure $ next res
interpretLangF coreRt (L.EvalControlFlow f next) = next <$> runControlFlowL coreRt f
-- interpretLangF coreRt (L.EvalLogger msg next) =
-- next <$> runLoggerL (coreRt ^. RLens.loggerRuntime . RLens.hsLoggerHandle) msg
-- interpretLangF _ (L.EvalRandom s next) = next <$> runRandomL s
interpretLangF coreRt (CL.EvalControlFlow f next) = next <$> runControlFlowL coreRt f
interpretLangF coreRt (CL.EvalLogger msg next) =
next <$> runLoggerL (coreRt ^. RLens.loggerRuntime . RLens.hsLoggerHandle) msg
interpretLangF _ (CL.EvalRandom s next) = next <$> runRandomL s
-- interpretLangF _ (L.EvalIO f next) = next <$> f
interpretLangF _ _ = error "Not implemented."

View File

@ -5,60 +5,68 @@ module Hydra.Core.Lang.ChurchL where
import Hydra.Prelude
import qualified Hydra.Core.ControlFlow.ChurchL as CL
import qualified Hydra.Core.Random.ChurchL as CL
import qualified Hydra.Core.Logger.ChurchL as CL
import qualified Hydra.Core.ControlFlow.Language as L
import qualified Hydra.Core.Logger.Language as L
import qualified Hydra.Core.Random.Language as L
import qualified Hydra.Core.State.Language as L
import qualified Hydra.Core.Random.Language as L
import qualified Hydra.Core.Logger.Language as L
import qualified Hydra.Core.ControlFlow.Class as L
import qualified Hydra.Core.Logger.Class as L
import qualified Hydra.Core.Random.Class as L
-- import qualified Hydra.Core.Logger.Language as L
-- import qualified Hydra.Core.Random.Language as L
-- import qualified Hydra.Core.State.Language as L
import Language.Haskell.TH.MakeFunctor (makeFunctorInstance)
-- | Core effects container language.
data LangF next where
-- | Eval stateful action atomically.
EvalStateAtomically :: L.StateL a -> (a -> next) -> LangF next
-- -- | Eval stateful action atomically.
-- EvalStateAtomically :: L.StateL a -> (a -> next) -> LangF next
-- | Logger effect
EvalLogger :: L.LoggerL () -> (() -> next) -> LangF next
EvalLogger :: CL.LoggerL () -> (() -> next) -> LangF next
-- | Random effect
EvalRandom :: L.RandomL a -> (a -> next) -> LangF next
EvalRandom :: CL.RandomL a -> (a -> next) -> LangF next
-- | ControlFlow effect
EvalControlFlow :: L.ControlFlowL a -> (a -> next) -> LangF next
-- | Impure effect. Avoid using it in production code (it's not testable).
EvalIO :: IO a -> (a -> next) -> LangF next
EvalControlFlow :: CL.ControlFlowL a -> (a -> next) -> LangF next
-- -- | Impure effect. Avoid using it in production code (it's not testable).
-- EvalIO :: IO a -> (a -> next) -> LangF next
makeFunctorInstance ''LangF
type LangL = Free LangF
type LangL = F LangF
class IOL m where
evalIO :: IO a -> m a
instance IOL LangL where
evalIO io = liftF $ EvalIO io id
-- | Eval stateful action atomically.
evalStateAtomically :: L.StateL a -> LangL a
evalStateAtomically action = liftF $ EvalStateAtomically action id
instance L.StateIO LangL where
atomically = evalStateAtomically
newVarIO = evalStateAtomically . L.newVar
readVarIO = evalStateAtomically . L.readVar
writeVarIO var = evalStateAtomically . L.writeVar var
evalLogger :: L.LoggerL () -> LangL ()
evalLogger logger = liftF $ EvalLogger logger id
-- class IOL m where
-- evalIO :: IO a -> m a
--
-- instance IOL LangL where
-- evalIO io = liftF $ EvalIO io id
--
-- -- | Eval stateful action atomically.
-- evalStateAtomically :: L.StateL a -> LangL a
-- evalStateAtomically action = liftF $ EvalStateAtomically action id
--
-- instance L.StateIO LangL where
-- atomically = evalStateAtomically
-- newVarIO = evalStateAtomically . L.newVar
-- readVarIO = evalStateAtomically . L.readVar
-- writeVarIO var = evalStateAtomically . L.writeVar var
--
evalLogger :: CL.LoggerL () -> LangL ()
evalLogger logger = liftFC $ EvalLogger logger id
instance L.Logger LangL where
logMessage level msg = evalLogger $ L.logMessage level msg
evalRandom :: L.RandomL a -> LangL a
evalRandom g = liftF $ EvalRandom g id
evalRandom :: CL.RandomL a -> LangL a
evalRandom g = liftFC $ EvalRandom g id
instance L.Random LangL where
getRandomInt = evalRandom . L.getRandomInt
evalControlFlow :: L.ControlFlowL a -> LangL a
evalControlFlow a = liftF $ EvalControlFlow a id
evalControlFlow :: CL.ControlFlowL a -> LangL a
evalControlFlow a = liftFC $ EvalControlFlow a id
instance L.ControlFlow LangL where
delay i = evalControlFlow $ L.delay i

View File

@ -4,8 +4,7 @@ import Hydra.Prelude
import Hydra.Core.ControlFlow.Interpreter (runControlFlowL)
import qualified Hydra.Core.Language as L
import Hydra.Core.Logger.Impl.HsLogger (runLoggerL)
import Hydra.Core.Random.Interpreter (runRandomL)
import Hydra.Core.Logger.Impl.HsLoggerInterpreter (runLoggerL)
import Hydra.Core.Random.Interpreter (runRandomL)
import qualified Hydra.Core.RLens as RLens
import qualified Hydra.Core.Runtime as R

View File

@ -8,6 +8,9 @@ import Hydra.Prelude
import qualified Hydra.Core.ControlFlow.Language as L
import qualified Hydra.Core.Logger.Language as L
import qualified Hydra.Core.Random.Language as L
import qualified Hydra.Core.ControlFlow.Class as L
import qualified Hydra.Core.Logger.Class as L
import qualified Hydra.Core.Random.Class as L
import qualified Hydra.Core.State.Language as L
import Language.Haskell.TH.MakeFunctor (makeFunctorInstance)

View File

@ -3,8 +3,11 @@ module Hydra.Core.Language
) where
import Hydra.Core.ControlFlow.Language as X
import Hydra.Core.ControlFlow.Class as X
import Hydra.Core.Lang.Language as X
import Hydra.Core.Logger.Language as X
import Hydra.Core.Logger.Class as X
import Hydra.Core.Process.Language as X
import Hydra.Core.Random.Class as X
import Hydra.Core.Random.Language as X
import Hydra.Core.State.Language as X

View File

@ -0,0 +1,15 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TemplateHaskell #-}
module Hydra.Core.Logger.ChurchL where
import Hydra.Prelude
import qualified Hydra.Core.Domain as D
import qualified Hydra.Core.Logger.Language as L
import qualified Hydra.Core.Logger.Class as L
type LoggerL = F L.LoggerF
instance L.Logger LoggerL where
logMessage level msg = liftFC $ L.LogMessage level msg id

View File

@ -0,0 +1,27 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TemplateHaskell #-}
module Hydra.Core.Logger.Class where
import Hydra.Prelude
import qualified Hydra.Core.Domain as D
class Logger m where
logMessage :: D.LogLevel -> D.Message -> m ()
-- | Log message with Info level.
logInfo :: Logger m => D.Message -> m ()
logInfo = logMessage D.Info
-- | Log message with Error level.
logError :: Logger m => D.Message -> m ()
logError = logMessage D.Error
-- | Log message with Debug level.
logDebug :: Logger m => D.Message -> m ()
logDebug = logMessage D.Debug
-- | Log message with Warning level.
logWarning :: Logger m => D.Message -> m ()
logWarning = logMessage D.Warning

View File

@ -9,7 +9,7 @@ import System.Log.Handler (close, setFormatter)
import System.Log.Handler.Simple (GenericHandler, fileHandler, streamHandler)
import System.Log.Logger
import qualified Hydra.Core.Domain as D (LogLevel (..), LoggerConfig (..))
import qualified Hydra.Core.Domain as D
import qualified Hydra.Core.Language as L
-- | Opaque type covering all information needed to teardown the logger.
@ -34,16 +34,6 @@ dispatchLogLevel D.Info = INFO
dispatchLogLevel D.Warning = WARNING
dispatchLogLevel D.Error = ERROR
-- | Interpret LoggerL language.
interpretLoggerL :: HsLoggerHandle -> L.LoggerF a -> IO a
interpretLoggerL _ (L.LogMessage level msg next) = do
logM component (dispatchLogLevel level) $ TXT.unpack msg
pure $ next ()
runLoggerL :: Maybe HsLoggerHandle -> L.LoggerL () -> IO ()
runLoggerL (Just h) l = foldFree (interpretLoggerL h) l
runLoggerL Nothing _ = pure ()
-- | Setup logger required by the application.
setupLogger :: D.LoggerConfig -> IO HsLoggerHandle
setupLogger (D.LoggerConfig format level logFileName isConsoleLog isFileLog) = do

View File

@ -0,0 +1,21 @@
module Hydra.Core.Logger.Impl.HsLoggerChurchI where
import Hydra.Prelude
import qualified Data.Text as TXT (unpack)
import System.IO (Handle, stdout)
import System.Log.Formatter
import System.Log.Handler (close, setFormatter)
import System.Log.Handler.Simple (GenericHandler, fileHandler, streamHandler)
import System.Log.Logger
import qualified Hydra.Core.Domain as D
import qualified Hydra.Core.ChurchL as CL
import qualified Hydra.Core.Language as L
import Hydra.Core.Logger.Impl.HsLogger
import qualified Hydra.Core.Logger.Impl.HsLoggerInterpreter as I
runLoggerL :: Maybe HsLoggerHandle -> CL.LoggerL () -> IO ()
runLoggerL (Just h) l = foldF (I.interpretLoggerF h) l
runLoggerL Nothing _ = pure ()

View File

@ -0,0 +1,25 @@
module Hydra.Core.Logger.Impl.HsLoggerInterpreter where
import Hydra.Prelude
import qualified Data.Text as TXT (unpack)
import System.IO (Handle, stdout)
import System.Log.Formatter
import System.Log.Handler (close, setFormatter)
import System.Log.Handler.Simple (GenericHandler, fileHandler, streamHandler)
import System.Log.Logger
import qualified Hydra.Core.Domain as D
import qualified Hydra.Core.Language as L
import Hydra.Core.Logger.Impl.HsLogger
-- | Interpret LoggerL language.
interpretLoggerF :: HsLoggerHandle -> L.LoggerF a -> IO a
interpretLoggerF _ (L.LogMessage level msg next) = do
logM component (dispatchLogLevel level) $ TXT.unpack msg
pure $ next ()
runLoggerL :: Maybe HsLoggerHandle -> L.LoggerL () -> IO ()
runLoggerL (Just h) l = foldFree (interpretLoggerF h) l
runLoggerL Nothing _ = pure ()

View File

@ -5,7 +5,9 @@ module Hydra.Core.Logger.Language where
import Hydra.Prelude
import qualified Hydra.Core.Domain as D (LogLevel (..), Message)
import qualified Hydra.Core.Domain as D
import Hydra.Core.Logger.Class
import Language.Haskell.TH.MakeFunctor
@ -18,24 +20,5 @@ makeFunctorInstance ''LoggerF
type LoggerL = Free LoggerF
class Logger m where
logMessage :: D.LogLevel -> D.Message -> m ()
instance Logger LoggerL where
logMessage level msg = liftF $ LogMessage level msg id
-- | Log message with Info level.
logInfo :: Logger m => D.Message -> m ()
logInfo = logMessage D.Info
-- | Log message with Error level.
logError :: Logger m => D.Message -> m ()
logError = logMessage D.Error
-- | Log message with Debug level.
logDebug :: Logger m => D.Message -> m ()
logDebug = logMessage D.Debug
-- | Log message with Warning level.
logWarning :: Logger m => D.Message -> m ()
logWarning = logMessage D.Warning

View File

@ -0,0 +1,14 @@
module Hydra.Core.Random.ChurchI where
import Hydra.Prelude
import System.Entropy
import System.Random hiding (next)
import qualified Hydra.Core.ChurchL as CL
import qualified Hydra.Core.Random.Interpreter as I
import qualified Hydra.Core.Language as L
-- | Interpret RandomL language.
runRandomL :: CL.RandomL a -> IO a
runRandomL = foldF I.interpretRandomF

View File

@ -0,0 +1,17 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE TemplateHaskell #-}
module Hydra.Core.Random.ChurchL where
import Hydra.Prelude
import qualified Hydra.Core.Random.Language as L
import qualified Hydra.Core.Random.Class as L
import Language.Haskell.TH.MakeFunctor
type RandomL = F L.RandomF
instance L.Random (F L.RandomF) where
getRandomInt range = liftFC $ L.GetRandomInt range id

View File

@ -0,0 +1,10 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE TemplateHaskell #-}
module Hydra.Core.Random.Class where
import Hydra.Prelude
class Random m where
getRandomInt :: (Int, Int) -> m Int

View File

@ -6,6 +6,8 @@ module Hydra.Core.Random.Language where
import Hydra.Prelude
import Hydra.Core.Random.Class
import Language.Haskell.TH.MakeFunctor
-- | Language for Random.
@ -15,10 +17,7 @@ data RandomF next where
makeFunctorInstance ''RandomF
type RandomL next = Free RandomF next
class Random m where
getRandomInt :: (Int, Int) -> m Int
type RandomL = Free RandomF
instance Random (Free RandomF) where
getRandomInt range = liftF $ GetRandomInt range id

View File

@ -7,6 +7,7 @@ import qualified Data.Map as Map
import qualified Hydra.Core.Domain as D
import qualified Hydra.Core.Language as L
import qualified Hydra.Core.Logger.Impl.HsLogger as Impl
import qualified Hydra.Core.Logger.Impl.HsLoggerInterpreter as I
-- | Runtime data for the concrete logger impl.
newtype LoggerRuntime = LoggerRuntime
@ -86,7 +87,7 @@ createCoreRuntime loggerRt = CoreRuntime
-- logWarning' :: RuntimeLogger -> D.Message -> IO ()
-- logWarning' (RuntimeLogger l) = l D.Warning
-- TODO: Church version of flusher.
-- | Writes all stm entries into real logger.
flushStmLogger :: StateRuntime -> LoggerRuntime -> IO ()
flushStmLogger stateRt loggerRt = do
@ -95,4 +96,4 @@ flushStmLogger stateRt loggerRt = do
writeTVar (_stmLog stateRt) []
pure l
let loggerHandle = _hsLoggerHandle loggerRt
mapM_ (\(D.LogEntry level msg) -> Impl.runLoggerL loggerHandle $ L.logMessage level msg) l
mapM_ (\(D.LogEntry level msg) -> I.runLoggerL loggerHandle $ L.logMessage level msg) l

View File

@ -6,6 +6,7 @@ module Hydra.Core.State.Language where
import Hydra.Prelude
import qualified Hydra.Core.Domain as D
import qualified Hydra.Core.Logger.Class as L
import qualified Hydra.Core.Logger.Language as L
import Language.Haskell.TH.MakeFunctor

View File

@ -18,8 +18,8 @@ import qualified Hydra.Framework.Runtime as R
-- langRunner :: R.CoreRuntime -> Impl.LangRunner CL.LangL
-- langRunner coreRt = Impl.LangRunner (Impl.runLangL coreRt)
interpretAppF :: R.CoreRuntime -> L.AppF a -> IO a
interpretAppF coreRt (L.EvalLang action next) = do
interpretAppF :: R.CoreRuntime -> CL.AppF a -> IO a
interpretAppF coreRt (CL.EvalLang action next) = do
res <- CI.runLangL coreRt action
pure $ next res

View File

@ -7,16 +7,28 @@ import Hydra.Prelude
import qualified Hydra.Core.Domain as D
import qualified Hydra.Core.Language as L
import qualified Hydra.Core.ChurchL as CL
import qualified Hydra.Framework.App.Language as L
type AppL = F L.AppF
import Language.Haskell.TH.MakeFunctor (makeFunctorInstance)
-- | Core effects container language.
data AppF next where
-- | Eval process.
-- EvalProcess :: L.ProcessL L.LangL a -> (a -> next) -> AppF next
-- | Eval lang.
EvalLang :: CL.LangL a -> (a -> next) -> AppF next
makeFunctorInstance ''AppF
type AppL = F AppF
-- | Eval lang.
evalLang :: L.LangL a -> AppL a
evalLang action = liftF $ L.EvalLang action id
evalLang :: CL.LangL a -> AppL a
evalLang action = liftFC $ EvalLang action id
-- | Eval lang.
scenario :: L.LangL a -> AppL a
scenario :: CL.LangL a -> AppL a
scenario = evalLang
--
-- -- | Eval process.
@ -38,12 +50,12 @@ scenario = evalLang
-- newVarIO = evalLang . L.newVarIO
-- readVarIO = evalLang . L.readVarIO
-- writeVarIO var = evalLang . L.writeVarIO var
--
-- instance L.Logger AppL where
-- logMessage level msg = evalLang $ L.logMessage level msg
--
-- instance L.Random AppL where
-- getRandomInt = evalLang . L.getRandomInt
instance L.Logger AppL where
logMessage level msg = evalLang $ L.logMessage level msg
instance L.Random AppL where
getRandomInt = evalLang . L.getRandomInt
instance L.ControlFlow AppL where
delay = evalLang . L.delay