           Nothing -> return (reverse acc)
   go []
 
-sendMessage :: o -> Rpc o i ()
+sendMessage :: req -> Rpc req resp ()
 sendMessage o = do
   crw <- askCrw
   encoder <- askEncoder
   x <- joinReply =<< liftIO (encoder o)
   joinReply =<< liftIO (clientWrite crw x)
 
-sendClose :: Rpc o i ()
+sendClose :: Rpc req resp ()
 sendClose = do
   crw <- askCrw
   joinReply =<< liftIO (clientSendClose crw)
 
-closeCall :: Rpc o i ()
+closeCall :: Rpc req resp ()
 closeCall = do
   crw <- askCrw
   liftIO (clientClose crw)

            _ -> return (RpcError (StatusError status statusDetails))
        RpcError err -> return (RpcError err)

data Client o i = Client { clientCrw :: ClientReaderWriter
                         , clientEncoder :: Encoder o
                         , clientDecoder :: Decoder i
                         }

type Decoder a = L.ByteString -> IO (RpcReply a)
type Encoder a = a -> IO (RpcReply B.ByteString)

  withMVar callMVar $ \call ->
  grpcCallDestroy call

type Rpc req resp a = ReaderT (Client req resp) (ExceptT RpcError IO) a

askCrw :: Rpc req resp ClientReaderWriter
askCrw = asks clientCrw

askDecoder :: Rpc req resp (Decoder resp)
askDecoder = asks clientDecoder

askEncoder :: Rpc req resp (Encoder req)
askEncoder = asks clientEncoder

joinReply :: RpcReply a -> Rpc req resp a
joinReply (RpcOk a) = return a
joinReply (RpcError err) = lift (throwE err)

withClient :: Client req resp -> Rpc req resp a -> IO (RpcReply a)
withClient client m = do
  e <- runExceptT (runReaderT m client)
  case e of
    Left err -> return (RpcError err)
    Right a -> return (RpcOk a)

receiveMessage :: Rpc req resp (Maybe resp)
receiveMessage = do
  crw <- askCrw
  msg <- joinReply =<< liftIO (clientRead crw)
