packages feed

typed-fsm-0.1.0.0: examples/turnstile/Main.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE QualifiedDo #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -Wno-unused-do-bind #-}

module Main where

import Control.Monad (void)
import Control.Monad.State
import qualified Data.Dependent.Map as D
import Data.Dependent.Sum
import Data.GADT.Compare (GCompare (..), GEq (..))
import Data.IFunctor as I
import Data.Singletons.Base.TH
import Data.Type.Equality (TestEquality (testEquality))
import TypedFsm

$(singletons [d|data TurnSt = Locked | Unlocked | Exit deriving (Show, Eq, Ord)|])

instance StateTransMsg TurnSt where
  data Msg TurnSt from to where
    Coin :: Msg TurnSt Locked Unlocked
    Push :: Msg TurnSt Unlocked Locked
    ExitTurnSt :: Msg TurnSt Locked Exit

instance GEq STurnSt where
  geq = testEquality

instance GCompare STurnSt where
  gcompare = sOrdToGCompare

lockedHandler :: Op TurnSt Int IO () Exit Locked
lockedHandler = I.do
  msg <- getInput
  case msg of
    Coin -> I.do
      liftm $ do
        liftIO $ putStrLn "Coin, internal int add one"
        modify' (+ 1)
        v <- get
        liftIO $ putStrLn $ "Now coin: " ++ show v
      unlockedHandler
    ExitTurnSt -> I.do
      liftm $ liftIO $ putStrLn "Exit turnSt"

unlockedHandler :: Op TurnSt Int IO () Exit Unlocked
unlockedHandler = I.do
  msg <- getInput
  case msg of
    Push -> I.do
      liftm $ do
        liftIO $ putStrLn "Push"
      lockedHandler

eventDepMap :: State2GenMsg TurnSt Int String
eventDepMap =
  D.fromList
    [ SLocked
        :=> GenMsg
          ( \_ ev -> case ev of
              "coin" -> Just $ SomeMsg Coin
              "exit" -> Just $ SomeMsg ExitTurnSt
              _ -> Nothing
          )
    , SUnlocked
        :=> GenMsg
          ( \_ ev -> case ev of
              "push" -> Just $ SomeMsg Push
              _ -> Nothing
          )
    ]

loop
  :: Result TurnSt (StateT Int IO) ()
  -> StateT Int IO ()
loop res = do
  case res of
    Finish _ -> liftIO $ putStrLn "Finish"
    NotMatchGenMsg singst -> liftIO $ putStrLn $ "NotMatch GenMSg: " ++ show singst
    Cont sop@(SomeOperate op) -> do
      st <- liftIO $ do
        putStrLn $ "current state: " ++ show (getSomeOperateSt sop)
        putStrLn "input command:"
        getLine
      nres <- runOp eventDepMap [st] op
      loop nres

main :: IO ()
main = do
  putStrLn "start loop"
  void $ runStateT (loop (Cont $ SomeOperate lockedHandler)) 0