File: Error.hs

package info (click to toggle)
haskell-arrows 0.4.4.2-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 152 kB
  • sloc: haskell: 917; makefile: 2
file content (189 lines) | stat: -rw-r--r-- 6,315 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Control.Arrow.Transformer.Error
-- Copyright   :  (c) Ross Paterson 2003
-- License     :  BSD-style (see the LICENSE file in the distribution)
--
-- Maintainer  :  R.Paterson@city.ac.uk
-- Stability   :  experimental
-- Portability :  non-portable (multi-parameter type classes)
--
-- An arrow transformer that adds error handling.
--
-- /TODO:/ the operations here are inconsistent with other arrow transformers.

module Control.Arrow.Transformer.Error(
    ErrorArrow(ErrorArrow),
    runError,
    ArrowAddError(..),
    ) where

import Control.Arrow.Internals
import Control.Arrow.Operations
import Control.Arrow.Transformer

import Control.Applicative
import Control.Arrow
import Control.Category
import Data.Monoid
#if (MIN_VERSION_base(4,9,0)) && !(MIN_VERSION_base(4,11,0))
import Data.Semigroup
#endif

import Prelude hiding (id,(.))

-- | An arrow that augments an existing arrow with possible errors.
-- The 'ArrowError' class contains methods for raising and handling
-- these errors.

newtype ErrorArrow ex a b c = ErrorArrow (a b (Either ex c))

rstrength :: (Either ex a, b) -> Either ex (a, b)
rstrength (Left ex, _) = Left ex
rstrength (Right a, b) = Right (a, b)

-- | Encapsulate an error-raising computation,
-- by completely handling any errors.
--
-- Typical usage in arrow notation:
--
-- >    proc p -> ...
-- >        body `runError` \ex -> handler

runError :: ArrowChoice a =>
    ErrorArrow ex a e b  -- ^ computation that may raise errors
    -> a (e,ex) b        -- ^ computation to handle errors
    -> a e b
runError (ErrorArrow f) h =
    arr id &&& f >>> arr strength >>> h ||| arr id
      where
        strength (x, Left y) = Left (x, y)
        strength (_, Right z) = Right z

-- transformer

instance ArrowChoice a => ArrowTransformer (ErrorArrow ex) a where
    lift f = ErrorArrow (f >>> arr Right)

-- liftings of standard classes

instance ArrowChoice a => Category (ErrorArrow ex a) where
    id = ErrorArrow (arr Right)
    ErrorArrow f . ErrorArrow g =
        ErrorArrow (arr (either Left id) . right f . g)

instance ArrowChoice a => Arrow (ErrorArrow ex a) where
    arr f = ErrorArrow (arr (Right . f))
    first (ErrorArrow f) = ErrorArrow (first f >>> arr rstrength)

instance ArrowChoice a => ArrowChoice (ErrorArrow ex a) where
    left (ErrorArrow f) = ErrorArrow (left f >>> arr assocsum)

assocsum :: Either (Either a b) c -> Either a (Either b c)
assocsum (Left (Left a)) = Left a
assocsum (Left (Right b)) = Right (Left b)
assocsum (Right c) = Right (Right c)

instance (ArrowChoice a, ArrowApply a) => ArrowApply (ErrorArrow ex a) where
    app = ErrorArrow (arr (\(ErrorArrow f, x) -> (f, x)) >>> app)

-- this instance has the right type, but it doesn't satisfy right
-- tightening, or sliding of non-strict functions.

instance (ArrowChoice a, ArrowLoop a) => ArrowLoop (ErrorArrow ex a) where
    loop (ErrorArrow f) = ErrorArrow (loop (f >>> arr dist))
      where
        dist x = (fstRight x, snd $ fromRight x)
        fstRight (Left x) = Left x
        fstRight (Right (x,_)) = Right x
        fromRight (Left _) = error "fromRight"
        fromRight (Right y) = y

-- Other instances

instance ArrowChoice a => Functor (ErrorArrow ex a b) where
    fmap f g = g >>> arr f

instance ArrowChoice a => Applicative (ErrorArrow ex a b) where
    pure x = arr (const x)
    f <*> g = f &&& g >>> arr (uncurry id)

instance (Monoid ex, ArrowChoice a) => Alternative (ErrorArrow ex a b) where
    empty = zeroArrow
    f <|> g = f <+> g

#if MIN_VERSION_base(4,9,0)
instance (Monoid ex, ArrowChoice a) => Semigroup (ErrorArrow ex a b c) where
    (<>) = (<+>)
#endif

instance (Monoid ex, ArrowChoice a) => Monoid (ErrorArrow ex a b c) where
    mempty = zeroArrow
#if !(MIN_VERSION_base(4,11,0))
    mappend = (<+>)
#endif

-- fresh instances

instance ArrowChoice a => ArrowError ex (ErrorArrow ex a) where
    raise = ErrorArrow (arr Left)
    handle (ErrorArrow f) (ErrorArrow h) =
        ErrorArrow (arr id &&& f >>> arr strength >>> h ||| arr Right)
      where
        strength (x, Left y) = Left (x, y)
        strength (_, Right z) = Right z
    tryInUnless (ErrorArrow f) (ErrorArrow s) (ErrorArrow h) =
        ErrorArrow (arr id &&& f >>> arr distr >>> h ||| s)
      where
        distr (b, Left ex) = Left (b, ex)
        distr (b, Right c) = Right (b, c)

instance ArrowChoice a => ArrowAddError ex (ErrorArrow ex a) a where
    liftError = lift
    elimError = runError

instance (Monoid ex, ArrowChoice a) => ArrowZero (ErrorArrow ex a) where
    zeroArrow = ErrorArrow (arr (const (Left mempty)))

instance (Monoid ex, ArrowChoice a) => ArrowPlus (ErrorArrow ex a) where
    f <+> g = handle f $ handle (arr fst >>> g) $
        ErrorArrow (arr (\((_,ex1), ex2) -> Left (ex1 `mappend` ex2)))

-- liftings of other arrow classes

-- specializations of general promotions

instance (ArrowReader r a, ArrowChoice a) =>
        ArrowReader r (ErrorArrow ex a) where
    readState = lift readState
    newReader (ErrorArrow f) = ErrorArrow (newReader f)

instance (ArrowState s a, ArrowChoice a) =>
        ArrowState s (ErrorArrow ex a) where
    fetch = lift fetch
    store = lift store

instance (ArrowWriter w a, ArrowChoice a) =>
        ArrowWriter w (ErrorArrow ex a) where
    write = lift write
    newWriter (ErrorArrow f) = ErrorArrow (newWriter f >>> arr rstrength)

-- promotions

instance (ArrowAddReader r a a', ArrowChoice a, ArrowChoice a') =>
        ArrowAddReader r (ErrorArrow ex a) (ErrorArrow ex a') where
    liftReader (ErrorArrow f) = ErrorArrow (liftReader f)
    elimReader (ErrorArrow f) = ErrorArrow (elimReader f)

instance (ArrowAddState s a a', ArrowChoice a, ArrowChoice a') =>
        ArrowAddState s (ErrorArrow ex a) (ErrorArrow ex a') where
    liftState (ErrorArrow f) = ErrorArrow (liftState f)
    elimState (ErrorArrow f) = ErrorArrow (elimState f >>> arr rstrength)

instance (ArrowAddWriter w a a', ArrowChoice a, ArrowChoice a') =>
        ArrowAddWriter w (ErrorArrow ex a) (ErrorArrow ex a') where
    liftWriter (ErrorArrow f) = ErrorArrow (liftWriter f)
    elimWriter (ErrorArrow f) = ErrorArrow (elimWriter f >>> arr rstrength)