Hi Javran,
1. Have you looked at iso lens? The lens library contextualizes isomorphisms among other interesting maps. Worth looking into.
2. Your code looks nicely idiomatic. You must have worked hard observing models of good haskell.
3. It's easy to declare at the type-level: a->b and b->a. It's just that the types don't say anything about whether they are isos or not. Whereas that's what we want.
Typically when I have such a pair of functions, I lean on quickcheck to give me a rapid verify as I tweak away, e.g.:
prop_encdecOk :: String -> Bool
prop_encdecOk xs = xs == (decode . encode $ xs)