packages feed

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 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. --