11module Data.Codec.Codec
22 ( -- * Codecs
33 Codec' (.. ), Codec
4+ , codec
45 , (>-<)
56 -- * Concrete codecs
67 , ConcreteCodec , concrete , parseVal , produceVal
@@ -18,15 +19,17 @@ 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 )
2325import Data.Profunctor
26+ import Data.Traversable (traverse )
2427
25- -- | De/serializer for the given types. Usually w ~ r, but they are separate
28+ -- | De/serializer for the given types. Usually ` w ~ r` , but they are separate
2629-- to allow for an `Applicative` instance.
2730data Codec' fr fw w r = Codec
2831 { parse :: fr r
29- , produce :: w -> fw ()
32+ , produce :: w -> fw r
3033 }
3134 deriving Functor
3235
@@ -35,12 +38,21 @@ type Codec fr fw a = Codec' fr fw a a
3538
3639-- Build up a serializer in parallel to a deserializer.
3740instance (Applicative fw , Applicative fr ) => Applicative (Codec' fr fw w ) where
38- pure x = Codec (pure x) (const $ pure () )
41+ pure x = Codec (pure x) (const $ pure x )
3942 Codec f fw <*> Codec x xw
40- = Codec (f <*> x) (\ w -> fw w *> xw w)
43+ = Codec (f <*> x) (\ w -> fw w <*> xw w)
44+
45+ instance (Monad fw , Monad fr ) => Monad (Codec' fr fw w ) where
46+ return x = Codec (return x) (const $ return x)
47+ Codec a aw >>= f
48+ = Codec (a >>= parse . f) (\ w -> aw w >>= \ a -> produce (f a) w)
49+
50+ -- | Constructor of basic codecs.
51+ codec :: Functor fw => fr r -> (r -> fw () ) -> Codec fr fw r
52+ codec parse produce = Codec parse (\ r -> r <$ produce r)
4153
4254-- | Associate a `Field` with a `Codec` to create a `Codec` `Build`.
43- (>-<) :: Functor fr => Field r a x y -> Codec fr fw a -> Build r (Codec' fr fw r ) x y
55+ (>-<) :: ( Functor fr , Functor fw ) => Field r a x y -> Codec fr fw a -> Build r (Codec' fr fw r ) x y
4456Field c g >-< Codec r w
4557 = Build (c <$> Codec r (w . g))
4658
@@ -49,7 +61,7 @@ Field c g >-< Codec r w
4961-- | Given a `Codec` for @a@, make one for `Maybe` @a@ that applies its deserializer optionally
5062-- and does nothing when serializing `Nothing`.
5163opt :: (Alternative fr , Applicative fw ) => Codec fr fw a -> Codec fr fw (Maybe a )
52- opt (Codec r w) = Codec (optional r) (maybe ( pure () ) w)
64+ opt (Codec r w) = Codec (optional r) (traverse w)
5365
5466instance Functor fr => Profunctor (Codec' fr fw ) where
5567 dimap from to (Codec r w)
@@ -63,10 +75,10 @@ mapCodec to from = dimap from to
6375-- the results are still complementary.
6476mapCodecM :: (Monad fr , Monad fw ) => (a -> fr b ) -> (b -> fw a ) -> Codec fr fw a -> Codec fr fw b
6577mapCodecM to from (Codec r w)
66- = Codec (r >>= to) (from >=> w )
78+ = Codec (r >>= to) (\ b -> from b >>= w >> return b )
6779
6880-- | Map the contexts of a given `Codec`.
69- mapCodecF :: (fr a -> gr a ) -> (fw () -> gw () ) -> Codec fr fw a -> Codec gr gw a
81+ mapCodecF :: (fr a -> gr a ) -> (fw a -> gw a ) -> Codec fr fw a -> Codec gr gw a
7082mapCodecF fr fw (Codec r w)
7183 = Codec (fr r) (fw . w)
7284
@@ -111,7 +123,7 @@ type PartialCodec fr fw a = Codec fr (Compose Maybe fw) a
111123-- | Finish a codec construction with a @`Con` r@ to produce a `PartialCodec`.
112124-- This will check that the given record has the appropriate constructor
113125-- before serializing.
114- cbuild :: (Functor fr , Buildable r y )
126+ cbuild :: (Functor fr , Functor fw , Buildable r y )
115127 => Con r x -> Build r (Codec' fr fw r ) x y -> PartialCodec fr fw r
116128cbuild (Con c p) = assume p . build c
117129
@@ -134,6 +146,6 @@ cd <-> acd = Codec
134146}
135147
136148-- | Attempt to get a serialization for a given value.
137- produceMaybe :: PartialCodec fr fw a -> a -> Maybe (fw () )
149+ produceMaybe :: PartialCodec fr fw a -> a -> Maybe (fw a )
138150produceMaybe (Codec _ w) x
139151 = getCompose (w x)
0 commit comments