# Towards monadic bidirectional serialization, a step back

Posted on October 13, 2016

This is written in Literate Haskell.

## Last episode

I proposed to extend `Codec`

as follows:

And so on. It was becoming quite sophisticated.

## A step back

Instead fix `produce`

to carry the `a`

type as well. In a way, this merges `produce_`

and `project_`

in a single field.

```
data Codec r w x a = Codec
{ parse :: r a
, produce :: x -> w a
}
instance (Functor r, Functor w)
=> Functor (Codec r w x) where
fmap f codec = Codec
{ parse = fmap f (parse codec)
, produce = fmap f . produce codec
}
instance (Applicative r, Applicative w)
=> Applicative (Codec r w x) where
pure a = Codec (pure a) (\_ -> pure a)
f <*> a = Codec
{ parse = parse f <*> parse a
, produce = \x -> produce f x <*> produce a x
}
-- We had lost this one for a moment
instance (Alternative r, Alternative w)
=> Alternative (Codec r w x) where
empty = Codec empty (\_ -> empty)
a <|> a' = Codec
{ parse = parse a <|> parse a'
, produce = \x -> produce a x <|> produce a' x
}
instance (Functor r, Functor w)
=> Profunctor (Codec r w) where
lmap from codec = codec
{ produce = produce codec . from
}
rmap = fmap
-- Hurray!
instance (Monad r, Monad w)
=> Monad (Codec r w x) where
a >>= f = Codec
{ parse = parse a >>= parse . f
, produce = \x ->
produce a x >>= \a -> produce (f a) x
}
```

Note that constraints are now symmetrical, `(Functor r, Functor w)`

and `(Monad r, Monad w)`

, instead of `Functor r`

and `(Monad r, Applicative w)`

, respectively.

In hindsight, the fact that previously we only ever used an `Applicative w`

was suspicious. We were actually relying on `w ()`

being a monoid. We might as well turn `w ()`

into a single variable `m`

.

```
-- Simplified Codec_
-- The same instances can be implemented with
-- a Monoid m constraint instead of Applicative w.
data CodecM r m x a = CodecM
{ parseM :: r a
, produceM :: x -> m
}
```

Our `Codec`

subsumes `CodecM`

(and thus `Codec_`

) via the following encoding:

```
-- We have Monoid m => Applicative (Const m)
codecMToCodec :: CodecM r m x a -> Codec r (Const m) x a
codecMToCodec a = Codec
{ parse = parseM a
, produce = Const . produceM a
}
codecToCodecM :: Codec r (Const m) x a -> CodecM r m x a
codecToCodecM a = CodecM
{ parseM = parse a
, produceM = getConst . produce a
}
```