diff options
Diffstat (limited to 'lib/FunctorToMaybe.hs')
-rw-r--r-- | lib/FunctorToMaybe.hs | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/lib/FunctorToMaybe.hs b/lib/FunctorToMaybe.hs new file mode 100644 index 0000000..658b024 --- /dev/null +++ b/lib/FunctorToMaybe.hs | |||
@@ -0,0 +1,69 @@ | |||
1 | --------------------------------------------------------------------------- | ||
2 | -- | | ||
3 | -- Module : FunctorToMaybe | ||
4 | -- | ||
5 | -- Maintainer : joe@jerkface.net | ||
6 | -- Stability : experimental | ||
7 | -- | ||
8 | -- Motivation: When parsing a stream of events, it is often desirable to | ||
9 | -- let certain control events pass-through to the output stream without | ||
10 | -- interrupting the parse. For example, the conduit package uses | ||
11 | -- <http://hackage.haskell.org/package/conduit-1.0.13.1/docs/Data-Conduit.html#t:Flush Flush> | ||
12 | -- which adds a special command to a stream and the blaze-builder-conduit | ||
13 | -- package has <http://hackage.haskell.org/package/blaze-builder-conduit-1.0.0/docs/Data-Conduit-Blaze.html#g:2 conduits> that treat the nullary constructor with special significance. | ||
14 | -- | ||
15 | -- But for other intermediary conduits, the nullary @Flush@ constructor may | ||
16 | -- be noise that they should politely preserve in case it is meaningul downstream. | ||
17 | -- If <http://hackage.haskell.org/package/conduit-1.0.13.1/docs/Data-Conduit.html#t:Flush Flush> | ||
18 | -- implemented the 'FunctorToMaybe' type class, then 'functorToEither' could be used to | ||
19 | -- seperate the noise from the work-product. | ||
20 | -- | ||
21 | {-# LANGUAGE CPP #-} | ||
22 | module FunctorToMaybe where | ||
23 | |||
24 | #if MIN_VERSION_base(4,6,0) | ||
25 | #else | ||
26 | import Control.Monad.Instances() | ||
27 | #endif | ||
28 | |||
29 | -- | The 'FunctorToMaybe' class genaralizes 'Maybe' in that the | ||
30 | -- there may be multiple null elements. | ||
31 | -- | ||
32 | -- Instances of 'FunctorToMaybe' should satisfy the following laws: | ||
33 | -- | ||
34 | -- > functorToMaybe (fmap f g) == fmap f (functorToMaybe g) | ||
35 | -- | ||
36 | class Functor g => FunctorToMaybe g where | ||
37 | functorToMaybe :: g a -> Maybe a | ||
38 | |||
39 | |||
40 | instance FunctorToMaybe Maybe where | ||
41 | functorToMaybe = id | ||
42 | instance FunctorToMaybe (Either a) where | ||
43 | functorToMaybe (Right x) = Just x | ||
44 | functorToMaybe _ = Nothing | ||
45 | |||
46 | |||
47 | -- | 'functorToEither' is a null-preserving cast. | ||
48 | -- | ||
49 | -- If @functorToMaybe g == Nothing@, then a casted value is returned with Left. | ||
50 | -- If @functorToMaybe g == Just a@, then @Right a@ is returned. | ||
51 | -- | ||
52 | -- Returning to our <http://hackage.haskell.org/package/conduit-1.0.13.1/docs/Data-Conduit.html#t:Flush Flush> | ||
53 | -- example, if we define | ||
54 | -- | ||
55 | -- > instance Flush where | ||
56 | -- > functorToMaybe Flush = Nothing | ||
57 | -- > functorToMaybe (Chunk a) = Just a | ||
58 | -- | ||
59 | -- Now stream processors can use 'functorToEither' to transform any nullary constructors while | ||
60 | -- while doing its work to transform the data before forwarding it into | ||
61 | -- <http://hackage.haskell.org/package/blaze-builder-conduit-1.0.0/docs/Data-Conduit-Blaze.html#v:builderToByteStringFlush builderToByteStringFlush>. | ||
62 | -- | ||
63 | functorToEither :: FunctorToMaybe f => f a -> Either (f b) a | ||
64 | functorToEither ga = | ||
65 | maybe (Left $ uncast ga) | ||
66 | Right | ||
67 | (functorToMaybe ga) | ||
68 | where | ||
69 | uncast = fmap (error "bad FunctorToMaybe instance") | ||