hal 0.4.10.1 → 1.0.0
raw patch · 6 files changed
+41/−315 lines, 6 filesdep −envyPVP ok
version bump matches the API change (PVP)
Dependencies removed: envy
API changes (from Hackage documentation)
- AWS.Lambda.Combinators: withFallibleInterface :: MonadReader c m => (c -> b -> Either String a) -> b -> m a
- AWS.Lambda.Combinators: withIOInterface :: (MonadReader c m, MonadIO m) => (c -> b -> IO (Either String a)) -> b -> m a
- AWS.Lambda.Combinators: withPureInterface :: MonadReader c m => (c -> b -> a) -> b -> m a
- AWS.Lambda.Context: class HasLambdaContext r
- AWS.Lambda.Context: defConfig :: DefConfig a => a
- AWS.Lambda.Context: instance AWS.Lambda.Context.HasLambdaContext AWS.Lambda.Context.LambdaContext
- AWS.Lambda.Context: instance System.Envy.DefConfig AWS.Lambda.Context.LambdaContext
- AWS.Lambda.Context: runReaderTLambdaContext :: ReaderT LambdaContext m a -> m a
- AWS.Lambda.Context: withContext :: HasLambdaContext r => LambdaContext -> r -> r
- AWS.Lambda.Runtime: mRuntimeWithContext' :: (MonadCatch m, MonadIO m, FromJSON event, ToJSON result) => (LambdaContext -> event -> m result) -> m ()
- AWS.Lambda.Runtime.Value: mRuntimeWithContext' :: (MonadCatch m, MonadIO m, ToJSON result) => (LambdaContext -> Value -> m result) -> m ()
- AWS.Lambda.Runtime: mRuntimeWithContext :: (HasLambdaContext r, MonadCatch m, MonadReader r m, MonadIO m, FromJSON event, ToJSON result) => (event -> m result) -> m ()
+ AWS.Lambda.Runtime: mRuntimeWithContext :: (MonadCatch m, MonadIO m, FromJSON event, ToJSON result) => (LambdaContext -> event -> m result) -> m ()
- AWS.Lambda.Runtime.Value: mRuntimeWithContext :: (HasLambdaContext r, MonadCatch m, MonadReader r m, MonadIO m, ToJSON result) => (Value -> m result) -> m ()
+ AWS.Lambda.Runtime.Value: mRuntimeWithContext :: (MonadCatch m, MonadIO m, ToJSON result) => (LambdaContext -> Value -> m result) -> m ()
Files
- CHANGELOG.md +16/−0
- hal.cabal +2/−3
- src/AWS/Lambda/Combinators.hs +5/−154
- src/AWS/Lambda/Context.hs +0/−26
- src/AWS/Lambda/Runtime.hs +6/−62
- src/AWS/Lambda/Runtime/Value.hs +12/−70
CHANGELOG.md view
@@ -5,6 +5,22 @@ The format is based on [Keep a Changelog][chg] and this project adheres to [Haskell's Package Versioning Policy][pvp] +## `1.0.0` - 2022-05-21++ - Remove deprecated functions and classes:+ - `AWS.Lambda.Combinators.withFallibleInterface`+ - `AWS.Lambda.Combinators.withIOInterface`+ - `AWS.Lambda.Combinators.withPureInterface`+ - `AWS.Lambda.Context.HasLambdaContext` (`class`)+ - `AWS.Lambda.Context.runReaderTLambdaContext`+ - `AWS.Lambda.Runtime.Value.mRuntimeWithContext`++ - Rename `mRuntimeWithContext'` to `mRuntimeWithContext` in the following modules:+ - `AWS.Lambda.Runtime`+ - `AWS.Lambda.Runtime.Value`++ - Remove dependency on `envy`+ ## `0.4.10.1` - 2022-03-28 - `instance FromJSON AWS.Lambda.Events.EventBridge.Detail.SSM.ParameterStoreChange.Operation`
hal.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 8dc55237df50c0c7ec3650a21ffaeb282db532546dc8cbe350c8be99621d2550+-- hash: 1cebfef05fdb7e4d5c45fee9770d3078f6d204cc9dde85b12386562678670e51 name: hal-version: 0.4.10.1+version: 1.0.0 synopsis: A runtime environment for Haskell applications running on AWS Lambda. description: This library uniquely supports different types of AWS Lambda Handlers for your needs/comfort with advanced Haskell. Instead of exposing a single function@@ -78,7 +78,6 @@ , conduit , conduit-extra , containers- , envy , exceptions , hashable , http-client
src/AWS/Lambda/Combinators.hs view
@@ -12,177 +12,28 @@ -} module AWS.Lambda.Combinators (- withIOInterface,- withFallibleInterface,- withPureInterface, withoutContext, withInfallibleParse ) where -import Control.Monad.IO.Class (MonadIO, liftIO)-import Control.Monad.Reader (MonadReader, ask) import Data.Aeson (FromJSON, parseJSON, Value) import Data.Aeson.Types (parseEither) ---- Helper for converting an either result into a monad/exception-dropEither :: Monad m => Either String a -> m a-dropEither = \case - Left e -> error e- Right x -> return x---- | Upgrades a handler that uses the `IO` monad with an `Either` inside into a--- base runtime handler.------ In the example below, we reconstruct 'AWS.Lambda.Runtime.ioRuntimeWithContext'--- without actually using it. The 'AWS.Lambda.Runtime.readerTRuntime' expects--- a handler in the form of @event -> ReaderT LambdaContext IO result@--- (ignoring constraints). By composing it with `withIOInterface` we get a new runtime which--- expects a function in the form of @LambdaContext -> event -> IO result@--- which matches that of `myHandler`.------ @--- {-\# LANGUAGE NamedFieldPuns, DeriveGeneric \#-}------ module Main where------ import AWS.Lambda.Context (LambdaContext(..))--- import AWS.Lambda.Runtime (readerTRuntime)--- import AWS.Lambda.Combinators (withIOInterface)--- import Data.Aeson (FromJSON)--- import Data.Text (unpack)--- import System.Environment (getEnv)--- import GHC.Generics (Generic)------ data Named = Named {--- name :: String--- } deriving Generic--- instance FromJSON Named------ myHandler :: LambdaContext -> Named -> IO (Either String String)--- myHandler (LambdaContext { functionName }) (Named { name }) = do--- greeting <- getEnv \"GREETING\"--- return $ if name == \"World\" then--- Right $ "Hello, World from " ++ unpack functionName ++ "!"--- else--- Left "Can only greet the world."------ main :: IO ()--- main = (readerTRuntime . withIOInterface) myHandler--- @-{-# DEPRECATED withIOInterface "This combinator is useful when combined with the current mRuntimeWithContext, which is deprecated." #-}-withIOInterface :: (MonadReader c m, MonadIO m) => (c -> b -> IO (Either String a)) -> (b -> m a)-withIOInterface fn event = do- config <- ask- result <- liftIO $ fn config event- dropEither result---- | Upgrades a handler that accepts 'AWS.Lambda.Context.LambdaContext' and--- an event to return a value inside an `Either` inside into a base runtime handler.------ In the example below, we reconstruct 'AWS.Lambda.Runtime.fallibleRuntimeWithContext'--- without actually using it. The 'AWS.Lambda.Runtime.readerTRuntime' expects a handler--- in the form of @event -> ReaderT LambdaContext IO result@ (ignoring constraints).--- By composing it with `withFallibleInterface` we get a new runtime which--- expects a function in the form of @LambdaContext -> event -> Either String result@--- which matches that of `myHandler`.------ @--- {-\# LANGUAGE NamedFieldPuns, DeriveGeneric \#-}------ module Main where------ import AWS.Lambda.Context (LambdaContext(..))--- import AWS.Lambda.Runtime (readerTRuntime)--- import AWS.Lambda.Combinators (withFallibleInterface)--- import Data.Aeson (FromJSON)--- import Data.Text (unpack)--- import GHC.Generics (Generic)------ data Named = Named {--- name :: String--- } deriving Generic--- instance FromJSON Named------ myHandler :: LambdaContext -> Named -> Either String String--- myHandler (LambdaContext { functionName }) (Named { name }) =--- if name == \"World\" then--- Right $ "Hello, World from " ++ unpack functionName ++ "!"--- else--- Left "Can only greet the world."------ main :: IO ()--- main = (readerTRuntime . withFallibleInterface) myHandler--- @-{-# DEPRECATED withFallibleInterface "This combinator is useful when combined with the current mRuntimeWithContext, which is deprecated." #-}-withFallibleInterface :: MonadReader c m => (c -> b -> Either String a) -> b -> m a-withFallibleInterface fn event = do- config <- ask- dropEither $ fn config event---- | This combinator takes a handler that accepts both an event and--- 'AWS.Lambda.Context.LambdaContext' and converts it into a handler that is--- compatible with the base monadic runtime.------ In the example below, we reconstruct 'AWS.Lambda.Runtime.pureRuntimeWithContext'--- without actually using it.--- The 'AWS.Lambda.Runtime.readerTRuntime' expects a handler in the form of--- @event -> ReaderT LambdaContext IO result@ (ignoring constraints).--- By composing it with `withPureInterface` we get a new runtime which--- expects a function in the form of @LambdaContext -> event -> result@--- which matches that of `myHandler`.------ @--- {-\# LANGUAGE NamedFieldPuns, DeriveGeneric \#-}------ module Main where------ import AWS.Lambda.Context (LambdaContext(..))--- import AWS.Lambda.Runtime (readerTRuntime)--- import AWS.Lambda.Combinators (withPureInterface)--- import Data.Aeson (FromJSON)--- import Data.Text (unpack)--- import GHC.Generics (Generic)------ data Named = Named {--- name :: String--- } deriving Generic--- instance FromJSON Named------ myHandler :: LambdaContext -> Named -> String--- myHandler (LambdaContext { functionName }) (Named { name }) =--- "Hello, " ++ name ++ " from " ++ unpack functionName ++ "!"------ main :: IO ()--- main = (readerTRuntime . withPureInterface) myHandler--- @-{-# DEPRECATED withPureInterface "This combinator is useful when combined with the current mRuntimeWithContext, which is deprecated." #-}-withPureInterface :: MonadReader c m => (c -> b -> a) -> b -> m a-withPureInterface fn event = do- config <- ask- return $ fn config event- -- | An alias of 'const', this upgrades a handler that does not accept -- 'AWS.Lambda.Context.LambdaContext' as its first curried argument to one that does. -- -- This allows us to use other combinators to construct a lambda runtime that accepts -- a handler that ignores 'AWS.Lambda.Context.LambdaContext'. ----- In the example below, we reconstruct 'AWS.Lambda.Runtime.pureRuntime' without actually using it.--- The 'AWS.Lambda.Runtime.readerTRuntime' expects a handler in the form of--- @event -> ReaderT LambdaContext IO result@ (ignoring constraints).--- By composing it with `withPureInterface` we get a new runtime which--- expects a function in the form of @LambdaContext -> event -> result@,--- And then finally we also compose `withoutContext` so it accepts the signature--- @event -> result@ which matches that of `myHandler`.---+-- In the example below, we reconstruct 'AWS.Lambda.Runtime.pureRuntime'+-- without actually using it. -- @ -- {-\# LANGUAGE NamedFieldPuns, DeriveGeneric \#-} -- -- module Main where ----- import AWS.Lambda.Runtime (readerTRuntime)--- import AWS.Lambda.Combinators (withPureInterface, withoutContext)+-- import AWS.Lambda.Runtime (pureRuntimeWithContext)+-- import AWS.Lambda.Combinators (withoutContext) -- import Data.Aeson (FromJSON) -- import GHC.Generics (Generic) --@@ -196,7 +47,7 @@ -- "Hello, " ++ name -- -- main :: IO ()--- main = (readerTRuntime . withPureInterface . withoutContext) myHandler+-- main = (pureRuntimeWithContext . withoutContext) myHandler -- @ withoutContext :: a -> b -> a withoutContext = const
src/AWS/Lambda/Context.hs view
@@ -15,21 +15,15 @@ CognitoIdentity(..), LambdaContext(..), getRemainingTime,- HasLambdaContext(..),- defConfig,- runReaderTLambdaContext ) where import Control.Monad.IO.Class (MonadIO, liftIO)-import Control.Monad.Reader (ReaderT, runReaderT) import Data.Aeson (FromJSON, ToJSON) import Data.Map (Map) import Data.Text (Text) import Data.Time.Clock (DiffTime, UTCTime, diffUTCTime, getCurrentTime)-import Data.Time.Clock.POSIX (posixSecondsToUTCTime) import GHC.Generics (Generic)-import System.Envy (DefConfig (..)) data ClientApplication = ClientApplication { appTitle :: Text,@@ -76,23 +70,3 @@ clientContext :: Maybe ClientContext, identity :: Maybe CognitoIdentity } deriving (Show, Generic, Eq)--{-# DEPRECATED HasLambdaContext "HasLambdaContext will be removed along with the original mRuntimeWithContext. This utility is no longer necessary without it." #-}-class HasLambdaContext r where- withContext :: (LambdaContext -> r -> r)--instance HasLambdaContext LambdaContext where- withContext = const---- TODO: This sticks around for backwards compatibility, and as a conevient-ish--- way to runReaderTLambdaContext. In the long term, all runtimes where the--- LambdaContext is (incorrectly) available outside of the request/response--- cycle will be removed. This instance (and its dependent package, envy) can--- be dropped on that breaking change.-instance DefConfig LambdaContext where- defConfig = LambdaContext "" "" 0 "" "" "" "" "" (posixSecondsToUTCTime 0) Nothing Nothing---- | Helper for using arbitrary monads with only the LambdaContext in its Reader-{-# DEPRECATED runReaderTLambdaContext "runReaderTLambdaContext will be removed along with the original mRuntimeWithContext. This particular approach was problematic, in that it required a default LambdaContext, when in reality, there is no valid instance." #-}-runReaderTLambdaContext :: ReaderT LambdaContext m a -> m a-runReaderTLambdaContext = flip runReaderT defConfig
src/AWS/Lambda/Runtime.hs view
@@ -25,33 +25,29 @@ ioRuntime, ioRuntimeWithContext, readerTRuntime,- mRuntimeWithContext', mRuntime, mRuntimeWithContext ) where import AWS.Lambda.Combinators (withInfallibleParse)-import AWS.Lambda.Context (LambdaContext(..), HasLambdaContext(..))+import AWS.Lambda.Context (LambdaContext(..)) import qualified AWS.Lambda.Runtime.Value as ValueRuntime import Control.Monad.Catch (MonadCatch) import Control.Monad.IO.Class (MonadIO)-import Control.Monad.Reader (MonadReader, ReaderT)+import Control.Monad.Reader (ReaderT) import Data.Aeson (FromJSON, ToJSON) -- | For any monad that supports 'IO' and 'catch'. Useful if you need -- caching behaviours or are comfortable manipulating monad -- transformers, and want full control over your monadic interface. ----- In a future version, this function will be renamed to--- @mRuntimeWithContext@ (after the deprecated function is removed).--- -- @ -- {-\# LANGUAGE DeriveGeneric, NamedFieldPuns \#-} -- -- module Main where -- -- import AWS.Lambda.Context (LambdaContext(..))--- import AWS.Lambda.Runtime (mRuntimeWithContext')+-- import AWS.Lambda.Runtime (mRuntimeWithContext) -- import Control.Monad.State.Lazy (StateT, evalStateT, get, put) -- import Control.Monad.Trans (liftIO) -- import Data.Aeson (FromJSON)@@ -74,11 +70,10 @@ -- return $ greeting ++ name ++ " (" ++ show greetingCount ++ ") from " ++ unpack functionName ++ "!" -- -- main :: IO ()--- main = evalStateT (mRuntimeWithContext' myHandler) 0+-- main = evalStateT (mRuntimeWithContext myHandler) 0 -- @-mRuntimeWithContext' :: (MonadCatch m, MonadIO m, FromJSON event, ToJSON result) => (LambdaContext -> event -> m result) -> m ()-mRuntimeWithContext' = ValueRuntime.mRuntimeWithContext' . fmap withInfallibleParse-+mRuntimeWithContext :: (MonadCatch m, MonadIO m, FromJSON event, ToJSON result) => (LambdaContext -> event -> m result) -> m ()+mRuntimeWithContext = ValueRuntime.mRuntimeWithContext . fmap withInfallibleParse -- | For any monad that supports 'IO' and 'catch'. Useful if you need -- caching behaviours or are comfortable manipulating monad@@ -116,57 +111,6 @@ -- @ mRuntime :: (MonadCatch m, MonadIO m, FromJSON event, ToJSON result) => (event -> m result) -> m () mRuntime = ValueRuntime.mRuntime . withInfallibleParse-----TODO: Revisit all names before we put them under contract--- | For any monad that supports IO\/catch\/Reader LambdaContext.------ This function is problematic, and has been deprecated. The--- 'HasLambdaContext' constraint requires that a 'LambdaContext' is--- settable in the @m@ monad, but that is not the case - we only have--- a 'LambdaContext' during the request/response cycle.------ If you need caching behavours or are comfortable manipulating monad--- transformers and want full control over your monadic interface,--- consider 'mRuntimeWithContext''.------ @--- {-\# LANGUAGE NamedFieldPuns, DeriveGeneric \#-}------ module Main where------ import AWS.Lambda.Context (LambdaContext(..), runReaderTLambdaContext)--- import AWS.Lambda.Runtime (mRuntimeWithContext)--- import Control.Monad.Reader (ReaderT, ask)--- import Control.Monad.State.Lazy (StateT, evalStateT, get, put)--- import Control.Monad.Trans (liftIO)--- import Data.Aeson (FromJSON)--- import Data.Text (unpack)--- import System.Environment (getEnv)--- import GHC.Generics (Generic)------ data Named = Named {--- name :: String--- } deriving Generic--- instance FromJSON Named------ myHandler :: Named -> StateT Int (ReaderT LambdaContext IO) String--- myHandler Named { name } = do--- LambdaContext { functionName } <- ask--- greeting <- liftIO $ getEnv \"GREETING\"------ greetingCount <- get--- put $ greetingCount + 1------ return $ greeting ++ name ++ " (" ++ show greetingCount ++ ") from " ++ unpack functionName ++ "!"------ main :: IO ()--- main = runReaderTLambdaContext (evalStateT (mRuntimeWithContext myHandler) 0)--- @-{-# DEPRECATED mRuntimeWithContext "mRuntimeWithContext will be replaced by mRuntimeWithContext' in a future version. This type signature makes impossible promises - see the haddock for details." #-}-mRuntimeWithContext :: (HasLambdaContext r, MonadCatch m, MonadReader r m, MonadIO m, FromJSON event, ToJSON result) =>- (event -> m result) -> m ()-mRuntimeWithContext = ValueRuntime.mRuntimeWithContext . withInfallibleParse -- | For functions that can read the lambda context and use IO within the same monad. --
src/AWS/Lambda/Runtime/Value.hs view
@@ -35,20 +35,19 @@ ioRuntime, ioRuntimeWithContext, readerTRuntime,- mRuntimeWithContext', mRuntime,- mRuntimeWithContext+ mRuntimeWithContext, ) where import AWS.Lambda.RuntimeClient (RuntimeClientConfig, getRuntimeClientConfig, getNextData, sendEventError, sendEventSuccess) import AWS.Lambda.Combinators (withoutContext)-import AWS.Lambda.Context (LambdaContext(..), HasLambdaContext(..))+import AWS.Lambda.Context (LambdaContext(..)) import Control.Exception (SomeException, displayException) import Control.Monad ((<=<), forever) import Control.Monad.Catch (MonadCatch, try) import Control.Monad.IO.Class (MonadIO, liftIO)-import Control.Monad.Reader (MonadReader, ReaderT, local, runReaderT)+import Control.Monad.Reader (ReaderT, runReaderT) import Data.Aeson (ToJSON, Value) import Data.Bifunctor (first) import Data.Text (unpack)@@ -79,9 +78,6 @@ -- caching behaviours or are comfortable manipulating monad -- transformers, and want full control over your monadic interface. ----- In a future version, this function will be renamed to--- @mRuntimeWithContext@ (after the deprecated function is removed).--- -- A contrived example, that parses the 'Value' argument directly -- instead of using the higher-level features in -- @AWS.Lambda.Runtime.Value@:@@ -92,7 +88,7 @@ -- module Main where -- -- import AWS.Lambda.Context (LambdaContext(..))--- import AWS.Lambda.Runtime (mRuntimeWithContext')+-- import AWS.Lambda.Runtime (mRuntimeWithContext) -- import Control.Monad.Catch (Exception, throwM) -- import Control.Monad.State.Lazy (StateT, evalStateT, get, put) -- import Control.Monad.Trans (liftIO)@@ -121,10 +117,10 @@ -- return $ greeting ++ name ++ " (" ++ show greetingCount ++ ") from " ++ unpack functionName ++ "!" -- -- main :: IO ()--- main = evalStateT (mRuntimeWithContext' myHandler) 0+-- main = evalStateT (mRuntimeWithContext myHandler) 0 -- @-mRuntimeWithContext' :: (MonadCatch m, MonadIO m, ToJSON result) => (LambdaContext -> Value -> m result) -> m ()-mRuntimeWithContext' fn = do+mRuntimeWithContext :: (MonadCatch m, MonadIO m, ToJSON result) => (LambdaContext -> Value -> m result) -> m ()+mRuntimeWithContext fn = do runtimeClientConfig <- liftIO getRuntimeClientConfig forever $ runtimeLoop runtimeClientConfig fn@@ -174,61 +170,7 @@ -- main = evalStateT (mRuntime myHandler) 0 -- @ mRuntime :: (MonadCatch m, MonadIO m, ToJSON result) => (Value -> m result) -> m ()-mRuntime = mRuntimeWithContext' . withoutContext---- | For any monad that supports IO\/catch\/Reader LambdaContext.------ This function is problematic, and has been deprecated. The--- 'HasLambdaContext' constraint requires that a 'LambdaContext' is--- settable in the @m@ monad, but that is not the case - we only have--- a 'LambdaContext' during the request/response cycle.------ If you need caching behavours or are comfortable manipulating monad--- transformers and want full control over your monadic interface,--- consider 'mRuntimeWithContext''.------ @--- {-\# LANGUAGE NamedFieldPuns, DeriveGeneric \#-}------ module Main where------ import AWS.Lambda.Context (LambdaContext(..), runReaderTLambdaContext)--- import AWS.Lambda.Runtime (mRuntimeWithContext)--- import Control.Monad.Reader (ReaderT, ask)--- import Control.Monad.State.Lazy (StateT, evalStateT, get, put)--- import Control.Monad.Trans (liftIO)--- import Data.Aeson (Value, FromJSON, parseJSON)--- import Data.Aeson.Types (parseMaybe)--- import Data.Text (unpack)--- import System.Environment (getEnv)--- import GHC.Generics (Generic)------ data Named = Named {--- name :: String--- } deriving Generic--- instance FromJSON Named------ myHandler :: Value -> StateT Int (ReaderT LambdaContext IO) String--- myHandler jsonAst =--- case parseMaybe parseJSON jsonAst of--- Nothing -> return $ "My name is HAL, what's yours?"--- Just Named { name } -> do--- LambdaContext { functionName } <- ask--- greeting <- liftIO $ getEnv \"GREETING\"------ greetingCount <- get--- put $ greetingCount + 1------ return $ greeting ++ name ++ " (" ++ show greetingCount ++ ") from " ++ unpack functionName ++ "!"------ main :: IO ()--- main = runReaderTLambdaContext (evalStateT (mRuntimeWithContext myHandler) 0)--- @-{-# DEPRECATED mRuntimeWithContext "mRuntimeWithContext will be replaced by mRuntimeWithContext' in a future version. This type signature makes impossible promises - see the haddock for details." #-}-mRuntimeWithContext :: (HasLambdaContext r, MonadCatch m, MonadReader r m, MonadIO m, ToJSON result) =>- (Value -> m result) -> m ()-mRuntimeWithContext fn = mRuntimeWithContext' (\lc -> local (withContext lc) . fn)-+mRuntime = mRuntimeWithContext . withoutContext -- | For functions that can read the lambda context and use IO within the same monad. --@@ -271,7 +213,7 @@ -- @ readerTRuntime :: ToJSON result => (Value -> ReaderT LambdaContext IO result) -> IO ()-readerTRuntime fn = mRuntimeWithContext' $ flip (runReaderT . fn)+readerTRuntime fn = mRuntimeWithContext $ flip (runReaderT . fn) -- | For functions with IO that can fail in a pure way (or via throw). --@@ -312,7 +254,7 @@ -- @ ioRuntimeWithContext :: ToJSON result => (LambdaContext -> Value -> IO (Either String result)) -> IO ()-ioRuntimeWithContext fn = mRuntimeWithContext' (\lc -> either error pure <=< liftIO . fn lc)+ioRuntimeWithContext fn = mRuntimeWithContext (\lc -> either error pure <=< liftIO . fn lc) -- | For functions with IO that can fail in a pure way (or via throw). --@@ -389,7 +331,7 @@ -- @ fallibleRuntimeWithContext :: ToJSON result => (LambdaContext -> Value -> Either String result) -> IO ()-fallibleRuntimeWithContext = mRuntimeWithContext' . fmap (fmap pure)+fallibleRuntimeWithContext = mRuntimeWithContext . fmap (fmap pure) -- | For pure functions that can still fail. --@@ -462,7 +404,7 @@ -- @ pureRuntimeWithContext :: ToJSON result => (LambdaContext -> Value -> result) -> IO ()-pureRuntimeWithContext = mRuntimeWithContext' . fmap (fmap pure)+pureRuntimeWithContext = mRuntimeWithContext . fmap (fmap pure) -- | For pure functions that can never fail. --