Today I wanted to investigate if it is possible to construct a data type in such a way, that it does not store the data of the type of its type signature, but another representation of it. So, here is my attempt of an GADT which has a type constructor of type a
, but a data constructor of type ByteString
.
{-# LANGUAGE GADTs #-}
import Data.ByteString.Char8
import Data.Serialize
data Serialized a where
MkSerialized :: (Serialize a) => ByteString -> Serialized a
Now I can define a decode'
function in the following way:
decode' :: (Serialize a) => Serialized a -> a
decode' (MkSerialized bs) = let Right r = (decode bs) in r
And it works:
let s = MkSerialized (encode "test") :: Serialized String
print $ decode' s -- prints "test"
My problem is now that I'd like Serialized
to be an instance of Functor
.
instance Functor Serialized where
fmap f (MkSerialized bs) = MkSerialized (encode (f (right (decode bs))))
where right (Right r) = r
But I get the error (Serialize b) can not be deduced. How can I constraint the Functor instance so that Serialize
is enforced in the fmap
?
Functor
doesn't allow constraints on the type parameters to be required. There's a restricted functor class,RFunctor
in thermonad
package. Maybe you can use that. – Daniel FischerFunctor
-- but I feel obligated to mention: Please don't useData.ByteString.Char8
by default! It's a broken module that encourages broken code. There are some uses for it sometimes, but your code works just as well withData.ByteString
, which doesn't encourage misunderstandings of Unicode. – shachafCoYoneda
-style data type likedata Serialized a where MkSerialized :: Serialize x => ByteString -> (x -> a) -> Serialized a
which stores a ByteString and a post-deserialization function, and which does have aFunctor
instance. But of course that defeats the purpose here. – shachaf