File: Error.hs

package info (click to toggle)
haskell-arrows 0.2-3
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 152 kB
  • ctags: 3
  • sloc: haskell: 664; makefile: 60; sh: 22
file content (150 lines) | stat: -rw-r--r-- 5,135 bytes parent folder | download | duplicates (2)
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
{-# OPTIONS_GHC -fglasgow-exts #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Control.Arrow.Transformer.Error
-- Copyright   :  (c) Ross Paterson 2003
-- License     :  BSD-style (see the LICENSE file in the distribution)
--
-- Maintainer  :  ross@soi.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,
		runError,
		ArrowAddError(..),
	) where

import Control.Arrow
import Control.Arrow.Internals
import Control.Arrow.Operations
import Control.Arrow.Transformer
import Data.Monoid

-- | 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 => Arrow (ErrorArrow ex a) where
	arr f = ErrorArrow (arr (Right . f))
	ErrorArrow f >>> ErrorArrow g =
		ErrorArrow (f >>> right g >>> arr (either Left id))
	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

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