-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathGeneric.hs
More file actions
124 lines (106 loc) · 3.59 KB
/
Generic.hs
File metadata and controls
124 lines (106 loc) · 3.59 KB
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
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Control.Monad.Codec.Generic
( SimplifyGeneric(..)
, match
, rchoose
, lchoose
, combine
, (|*|)
, (?>)
, (<?)
) where
import Control.Applicative
import Control.Monad.Codec
import Data.Profunctor
import GHC.Generics
-- | A class providing functions to convert between generics and structures made of `Either` and ( , )
class SimplifyGeneric a where
type SimpleGeneric a :: *
simplifyGeneric :: a p -> SimpleGeneric a
unsimplifyGeneric :: SimpleGeneric a -> a p
instance SimplifyGeneric U1 where
type SimpleGeneric U1 = ()
simplifyGeneric = const ()
unsimplifyGeneric = const U1
instance SimplifyGeneric (K1 i c) where
type SimpleGeneric (K1 i c) = c
simplifyGeneric = unK1
unsimplifyGeneric = K1
instance SimplifyGeneric f => SimplifyGeneric (M1 i c f) where
type SimpleGeneric (M1 i c f) = SimpleGeneric f
simplifyGeneric = simplifyGeneric . unM1
unsimplifyGeneric = M1 . unsimplifyGeneric
instance (SimplifyGeneric a, SimplifyGeneric b) =>
SimplifyGeneric (a :+: b) where
type SimpleGeneric (a :+: b) = Either (SimpleGeneric a) (SimpleGeneric b)
simplifyGeneric (L1 x) = Left $ simplifyGeneric x
simplifyGeneric (R1 x) = Right $ simplifyGeneric x
unsimplifyGeneric (Left x) = L1 $ unsimplifyGeneric x
unsimplifyGeneric (Right x) = R1 $ unsimplifyGeneric x
instance (SimplifyGeneric a, SimplifyGeneric b) =>
SimplifyGeneric (a :*: b) where
type SimpleGeneric (a :*: b) = (SimpleGeneric a, SimpleGeneric b)
simplifyGeneric (a :*: b) = (simplifyGeneric a, simplifyGeneric b)
unsimplifyGeneric (a, b) = unsimplifyGeneric a :*: unsimplifyGeneric b
-- | Construct a codec for any type using the `Generic` instance.
-- The codec is usually obtained by using `combine`, `lchoose` and `rchoose`
match ::
(Generic a, Functor r, Functor w, SimplifyGeneric (Rep a))
=> Codec r w (SimpleGeneric (Rep a))
-> Codec r w a
match = dimap (simplifyGeneric . from) (to . unsimplifyGeneric)
-- | Combine two codecs to read / write a tuple of values
combine ::
(Applicative r, Applicative w)
=> CodecFor r w a b
-> CodecFor r w c d
-> CodecFor r w (a, c) (b, d)
combine a b = (,) <$> fst =. a <*> snd =. b
-- | Operator for `combine`
(|*|) ::
(Applicative r, Applicative w)
=> CodecFor r w a b
-> CodecFor r w c d
-> CodecFor r w (a, c) (b, d)
(|*|) = combine
infixl 7 |*|
-- | Combine two codecs to read / write `Either` using `Left` as default when reading
lchoose ::
(Alternative r, Functor w)
=> Codec r w a
-> Codec r w b
-> Codec r w (Either a b)
lchoose l r =
Codec
{ codecIn = (Left <$> codecIn l) <|> (Right <$> codecIn r)
, codecOut = either (fmap Left . codecOut l) (fmap Right . codecOut r)
}
-- | Operator for `lchoose`
(?>) ::
(Alternative r, Functor w)
=> Codec r w a
-> Codec r w b
-> Codec r w (Either a b)
(?>) = lchoose
infixl 6 ?>
-- | Combine two codecs to read / write `Either` using `Right` as default when reading
rchoose ::
(Alternative r, Functor w)
=> Codec r w a
-> Codec r w b
-> Codec r w (Either a b)
rchoose l r =
Codec
{ codecIn = (Right <$> codecIn r) <|> (Left <$> codecIn l)
, codecOut = either (fmap Left . codecOut l) (fmap Right . codecOut r)
}
-- | Operator for `rchoose`
(<?) ::
(Alternative r, Functor w)
=> Codec r w a
-> Codec r w b
-> Codec r w (Either a b)
(<?) = rchoose
infixl 6 <?