packages feed

foldl-exceptions (empty) → 1.0.0.0

raw patch · 5 files changed

+269/−0 lines, 5 filesdep +basedep +doctestdep +foldl

Dependencies added: base, doctest, foldl, safe-exceptions

Files

+ changelog.md view
@@ -0,0 +1,3 @@+1.0.0.0++  * Initial release
+ foldl-exceptions.cabal view
@@ -0,0 +1,46 @@+cabal-version: 2.0++name: foldl-exceptions+version: 1.0.0.0++synopsis: Exception handling with FoldM+category: Web++description:+    Adds support for tuning exception handling behavior when+    using @FoldM@ from the @foldl@ package.++homepage:    https://github.com/typeclasses/foldl-exceptions+bug-reports: https://github.com/typeclasses/foldl-exceptions/issues++author:     Chris Martin+maintainer: Chris Martin, Julie Moronuki++copyright: 2018 Typeclass Consulting, LLC+license: MIT+license-file: license.txt++build-type: Simple+tested-with: GHC==8.6.1++extra-source-files:+    changelog.md++library+    hs-source-dirs: library+    default-language: Haskell2010++    exposed-modules:+        Control.Foldl.Exceptions++    build-depends:+        base >=4.10 && <5+      , foldl+      , safe-exceptions++test-suite doctest+    type: exitcode-stdio-1.0+    hs-source-dirs: test+    default-language: Haskell2010+    main-is: doctest.hs+    build-depends: base, doctest
+ library/Control/Foldl/Exceptions.hs view
@@ -0,0 +1,199 @@+{-# OPTIONS_GHC -Wall #-}++{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications    #-}++{- |++When 'IO' is the monad of a monadic fold, each step in the evaluation of the+fold might throw an exception, thus causing the entire evaluation to fail. This+module provides some functions for capturing the results from /part of/ a fold+even if some of the steps did not succeed.++This module uses 'try' from the @safe-exceptions@ package and will not catch+async exceptions.++-}++module Control.Foldl.Exceptions+  (+  -- * Stopping at the first exception+    exHalt_, exHalt++  -- * Continuing past failed steps+  , exSkip_, exSkip++  ) where++-- foldl+import Control.Foldl++-- safe-exceptions+import Control.Exception.Safe (Exception, MonadCatch, SomeException, try)++{- |++Performs the steps of a fold up until the first step that throws an exception,+then produces the result obtained thus far.++==== Example++>>> import Control.Exception+>>> f x = if x < 10 then return x else throw Overflow+>>> xs = [1, 2, 500, 4] :: [Integer]++Since @f 500@ produces an exception, the following fold fails:++>>> fold1 = premapM f (generalize list)+>>> foldM fold1 xs+*** Exception: arithmetic overflow++By applying 'untilFirstException', we can produce a new fold that returns+the intermediate result at the point where the exception occurs.++>>> fold2 = exHalt_ fold1+>>> foldM fold2 xs+[1,2]++-}++exHalt_ :: forall m a b.+    (Monad m, MonadCatch m) => FoldM m a b -> FoldM m a b++exHalt_ f = fmap snd (exHalt @SomeException f)++{- |++Performs the steps of a fold up until the first step that throws an exception,+then produces a tuple containing:++  1. The exception that was thrown, if any.+  2. The result obtained thus far.++The first type parameter lets you specify what type of exception to catch. Any+other type of exception will still cause the entire fold's evaluation to fail.++==== Example++>>> import Control.Exception+>>> f x = if x < 10 then return x else throw Overflow+>>> xs = [1, 2, 500, 4] :: [Integer]+>>> fold1 = premapM f (generalize list)++>>> :set -XTypeApplications+>>> fold2 = exHalt @ArithException fold1++>>> foldM fold2 xs+(Just arithmetic overflow,[1,2])++-}++exHalt :: forall e m a b.+    (Exception e, Monad m, MonadCatch m) =>+    FoldM m a b -> FoldM m a (Maybe e, b)++exHalt (FoldM step begin done) = FoldM step' begin' done'+  where+    begin' =+      do+        y <- begin+        return (Nothing, y)++    step' x'@(Just _, _) _ = return x'+    step' (Nothing, x1) a =+      do+        x2Either <- try (step x1 a)+        case x2Either of+            Left e   -> return (Just e, x1)+            Right x2 -> return (Nothing, x2)++    done' (eMaybe, x) =+      do+        b <- done x+        return (eMaybe, b)++{- |++Perform only steps of a fold that succeed, ignoring any steps that fail.++==== Example++>>> import Control.Exception+>>> f x = if x < 10 then return x else throw Overflow+>>> xs = [1, 2, 500, 4] :: [Integer]++Since @f 500@ produces an exception, the following fold fails:++>>> fold1 = premapM f (generalize list)+>>> foldM fold1 xs+*** Exception: arithmetic overflow++By applying 'exSkip_', we can produce a new fold that produces a result from all+steps that /don't/ fail:++>>> fold2 = exSkip_ fold1+>>> foldM fold2 xs+[1,2,4]++-}++exSkip_ :: forall m a b.+    (Monad m, MonadCatch m) => FoldM m a b -> FoldM m a b++exSkip_ f = fmap snd (exSkip @SomeException f)++{- |++Perform only steps of a fold that succeed, collecting the exceptions thrown from+each step that fail. Produces a tuple containing:++  1. A list of any exceptions thrown.+  2. The result obtained from the steps that succeeded.++The first type parameter lets you specify what type of exception to catch. Any+other type of exception will still cause the entire fold's evaluation to fail.++==== Example++>>> import Control.Exception+>>> f x = if x < 10 then return x else throw Overflow+>>> xs = [1, 2, 500, 4] :: [Integer]++Since @f 500@ produces an exception, the following fold fails:++>>> fold1 = premapM f (generalize list)+>>> foldM fold1 xs+*** Exception: arithmetic overflow++By applying 'exSkip', we can produce a new fold that produces a result from all+steps that /don't/ fail:++>>> :set -XTypeApplications+>>> fold2 = exSkip @ArithException fold1+>>> foldM fold2 xs+([arithmetic overflow],[1,2,4])++-}++exSkip :: forall e m a b.+    (Exception e, Monad m, MonadCatch m) =>+    FoldM m a b -> FoldM m a ([e], b)++exSkip (FoldM step begin done) = FoldM step' begin' done'+  where+    begin' =+      do+        y <- begin+        return (id, y)++    step' (es, x1) a =+      do+        x2Either <- try (step x1 a)+        case x2Either of+            Left e   -> return (es . (e :), x1)+            Right x2 -> return (es, x2)++    done' (es, x) =+      do+        b <- done x+        return (es [], b)
+ license.txt view
@@ -0,0 +1,18 @@+Copyright 2019 Typeclass Consulting, LLC++Permission is hereby granted, free of charge, to any person obtaining a copy of+this software and associated documentation files (the "Software"), to deal in+the Software without restriction, including without limitation the rights to+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of+the Software, and to permit persons to whom the Software is furnished to do so,+subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ test/doctest.hs view
@@ -0,0 +1,3 @@+import Test.DocTest++main = doctest ["library/Control/Foldl/Exceptions.hs"]