11module Data.Codec.Codec
22 ( -- * Codecs
33 Codec' (.. ), Codec
4+ , codec
45 , (>-<)
56 -- * Concrete codecs
67 , ConcreteCodec , concrete , parseVal , produceVal
@@ -18,14 +19,16 @@ import Control.Applicative
1819import Control.Monad ((>=>) )
1920import Control.Monad.Reader (ReaderT (.. ))
2021import Data.Codec.Field
22+ import Data.Functor ((<$) )
2123import Data.Functor.Compose
2224import Data.Maybe (fromMaybe )
25+ import Data.Traversable (traverse )
2326
24- -- | De/serializer for the given types. Usually w ~ r, but they are separate
27+ -- | De/serializer for the given types. Usually ` w ~ r` , but they are separate
2528-- to allow for an `Applicative` instance.
2629data Codec' fr fw w r = Codec
2730 { parse :: fr r
28- , produce :: w -> fw ()
31+ , produce :: w -> fw r
2932 }
3033 deriving Functor
3134
@@ -34,12 +37,21 @@ type Codec fr fw a = Codec' fr fw a a
3437
3538-- Build up a serializer in parallel to a deserializer.
3639instance (Applicative fw , Applicative fr ) => Applicative (Codec' fr fw w ) where
37- pure x = Codec (pure x) (const $ pure () )
40+ pure x = Codec (pure x) (const $ pure x )
3841 Codec f fw <*> Codec x xw
39- = Codec (f <*> x) (\ w -> fw w *> xw w)
42+ = Codec (f <*> x) (\ w -> fw w <*> xw w)
43+
44+ instance (Monad fw , Monad fr ) => Monad (Codec' fr fw w ) where
45+ return x = Codec (return x) (const $ return x)
46+ Codec a aw >>= f
47+ = Codec (a >>= parse . f) (\ w -> aw w >>= \ a -> produce (f a) w)
48+
49+ -- | Constructor of basic codecs.
50+ codec :: Functor fw => fr r -> (r -> fw () ) -> Codec fr fw r
51+ codec parse produce = Codec parse (\ r -> r <$ produce r)
4052
4153-- | Associate a `Field` with a `Codec` to create a `Codec` `Build`.
42- (>-<) :: Functor fr => Field r a x y -> Codec fr fw a -> Build r (Codec' fr fw r ) x y
54+ (>-<) :: ( Functor fr , Functor fw ) => Field r a x y -> Codec fr fw a -> Build r (Codec' fr fw r ) x y
4355Field c g >-< Codec r w
4456 = Build (c <$> Codec r (w . g))
4557
@@ -48,29 +60,29 @@ Field c g >-< Codec r w
4860-- | Given a `Codec` for @a@, make one for `Maybe` @a@ that applies its deserializer optionally
4961-- and does nothing when serializing `Nothing`.
5062opt :: (Alternative fr , Applicative fw ) => Codec fr fw a -> Codec fr fw (Maybe a )
51- opt (Codec r w) = Codec (optional r) (maybe ( pure () ) w)
63+ opt (Codec r w) = Codec (optional r) (traverse w)
5264
5365-- | Turn a @`Codec` a@ into a @`Codec` b@ by providing an isomorphism.
54- mapCodec :: Functor fr => (a -> b ) -> (b -> a ) -> Codec fr fw a -> Codec fr fw b
66+ mapCodec :: ( Functor fr , Functor fw ) => (a -> b ) -> (b -> a ) -> Codec fr fw a -> Codec fr fw b
5567mapCodec = mapCodec'
5668
5769-- | Map a field codec monadically. Useful for error handling but care must be taken to make sure that
5870-- the results are still complementary.
5971mapCodecM :: (Monad fr , Monad fw ) => (a -> fr b ) -> (b -> fw a ) -> Codec fr fw a -> Codec fr fw b
6072mapCodecM to from (Codec r w)
61- = Codec (r >>= to) (from >=> w )
73+ = Codec (r >>= to) (\ b -> from b >>= w >> return b )
6274
6375-- | Map the contexts of a given `Codec`.
64- mapCodecF :: (fr a -> gr a ) -> (fw () -> gw () ) -> Codec fr fw a -> Codec gr gw a
76+ mapCodecF :: (fr a -> gr a ) -> (fw a -> gw a ) -> Codec fr fw a -> Codec gr gw a
6577mapCodecF fr fw (Codec r w)
6678 = Codec (fr r) (fw . w)
6779
6880-- | Independently map the two components of a `Codec'`.
6981--
7082-- Generalizes `mapCodec`.
71- mapCodec' :: Functor fr => (a -> b ) -> (c -> d ) -> Codec' fr fw d a -> Codec' fr fw c b
83+ mapCodec' :: ( Functor fr , Functor fw ) => (a -> b ) -> (c -> d ) -> Codec' fr fw d a -> Codec' fr fw c b
7284mapCodec' to from (Codec r w)
73- = Codec ( to <$> r) (w . from)
85+ = fmap to $ Codec r (w . from)
7486
7587-- | Map on the `produce` component of a `Codec`.
7688--
@@ -113,7 +125,7 @@ type PartialCodec fr fw a = Codec fr (Compose Maybe fw) a
113125-- | Finish a codec construction with a @`Con` r@ to produce a `PartialCodec`.
114126-- This will check that the given record has the appropriate constructor
115127-- before serializing.
116- cbuild :: (Functor fr , Buildable r y )
128+ cbuild :: (Functor fr , Functor fw , Buildable r y )
117129 => Con r x -> Build r (Codec' fr fw r ) x y -> PartialCodec fr fw r
118130cbuild (Con c p) = assume p . build c
119131
@@ -136,6 +148,6 @@ cd <-> acd = Codec
136148}
137149
138150-- | Attempt to get a serialization for a given value.
139- produceMaybe :: PartialCodec fr fw a -> a -> Maybe (fw () )
151+ produceMaybe :: PartialCodec fr fw a -> a -> Maybe (fw a )
140152produceMaybe (Codec _ w) x
141153 = getCompose (w x)
0 commit comments