packages feed

MultiChor-1.0.0.0: examples/KVS7SimplePoly.hs

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}

module KVS7SimplePoly where

-- # This example was carried over from earlier work, likely HasChor. It doesn't yet have a unit test attached to it.

import Choreography
import Data.IORef (IORef, newIORef, readIORef)

type Response = Int

type Key = String

type State = String

errorResponse :: Response
errorResponse = -1

data Request
  = Get Key
  | Put Key Int
  deriving (Eq, Read, Show)

handleGet :: IORef State -> Key -> IO Response
handleGet s k = do
  readIORef s >>= putStrLn
  return $ length k

handlePut :: IORef State -> Key -> Int -> IO Response
handlePut s k v = do
  readIORef s >>= putStrLn
  return . fromEnum $ v /= length k

isOk :: Response -> Bool
isOk = (== 0)

handleRequest ::
  forall backups.
  (KnownSymbols backups) =>
  Located '["primary"] Request ->
  (Located '["primary"] (IORef State), Faceted backups '[] (IORef State)) ->
  Choreo ("primary" ': backups) IO (Located '["primary"] Response)
handleRequest request (primaryStateRef, backupsStateRefs) =
  broadcast (primary, request) >>= \case
    Put key value -> do
      oks <- parallel backups \backup un ->
        handlePut (viewFacet un backup backupsStateRefs) key value
      gathered <- gather backups (primary @@ nobody) oks
      locally primary \un ->
        if all isOk (un primary gathered)
          then handlePut (un primary primaryStateRef) key value
          else return errorResponse
    Get key -> locally primary \un -> handleGet (un primary primaryStateRef) key
  where
    primary :: forall ps. Member "primary" ("primary" ': ps)
    primary = listedFirst
    backups = consSuper refl

kvs ::
  forall backups.
  (KnownSymbols backups) =>
  Located '["client"] Request ->
  (Located '["primary"] (IORef State), Faceted backups '[] (IORef State)) ->
  Choreo ("client" ': "primary" ': backups) IO (Located '["client"] Response)
kvs request stateRefs = do
  request' <- (client, request) ~> primary @@ nobody
  response <- enclave (primary @@ backups) (handleRequest request' stateRefs)
  (primary, flatten (First @@ nobody) (First @@ nobody) response) ~> client @@ nobody
  where
    client :: forall ps. Member "client" ("client" ': ps)
    primary :: forall ps p. Member "primary" (p ': "primary" ': ps)
    client = listedFirst
    primary = listedSecond
    backups = consSuper $ consSuper refl

mainChoreo :: (KnownSymbols backups) => Choreo ("client" ': "primary" ': backups) IO ()
mainChoreo = do
  stateRef <- primary `_locally` newIORef "I'm Primary"
  bStRefs <- parallel backups \p _ -> newIORef ("I'm " ++ toLocTm p)
  loop (stateRef, bStRefs)
  where
    primary :: forall ps p. Member "primary" (p ': "primary" ': ps)
    primary = listedSecond
    client :: forall ps. Member "client" ("client" ': ps)
    client = listedFirst
    backups = consSuper $ consSuper refl
    loop state = do
      request <- _locally client $ read @Request <$> getLine
      response <- kvs request state
      client `locally_` \un -> do putStrLn ("> " ++ show (un client response))
      loop state

main :: IO ()
main = runChoreo (mainChoreo @'["A", "B", "C", "D", "E", "F"])