Dzisiaj chciałem zbadać, czy możliwe jest skonstruowanie typu danych w taki sposób, aby nie przechowywać danych typu typu jego sygnatury, ale inną reprezentację tego typu . Oto moja próba GADT, który ma typ konstruktora typu a
, ale konstruktora danych typu ByteString
.Instancja Functor dla GADT z ograniczeniem typu
{-# LANGUAGE GADTs #-}
import Data.ByteString.Char8
import Data.Serialize
data Serialized a where
MkSerialized :: (Serialize a) => ByteString -> Serialized a
Teraz mogę zdefiniować decode'
funkcję w następujący sposób:
decode' :: (Serialize a) => Serialized a -> a
decode' (MkSerialized bs) = let Right r = (decode bs) in r
I to działa:
let s = MkSerialized (encode "test") :: Serialized String
print $ decode' s -- prints "test"
Mój problem jest teraz, że chciałbym być Serialized
wystąpienie Functor
.
instance Functor Serialized where
fmap f (MkSerialized bs) = MkSerialized (encode (f (right (decode bs))))
where right (Right r) = r
Ale pojawia się błąd (Serialize b) nie można wywnioskować. W jaki sposób można ograniczyć instancję Functor, aby Serialize
została wymuszona w ?
Nie możesz. 'Funktor' nie zezwala na wymagania dotyczące parametrów typu. W pakiecie 'rmonad' jest klasa ograniczonego funktora, [' RFunctor'] (http://hackage.haskell.org/packages/archive/rmonad/0.8/doc/html/Control-RMonad.html#t:RFunctor) . Może możesz tego użyć. –
Nie jest to związane z twoim pytaniem - nie jest to możliwe z 'Functor' - ale czuję się zobowiązany wspomnieć: nie używaj domyślnie' Data.ByteString.Char8'! To uszkodzony moduł, który zachęca do zepsutego kodu. Czasami są na to sposoby, ale twój kod działa równie dobrze z 'Data.ByteString', co nie zachęca do nieporozumień w Unicode. – shachaf
Dla tego, co jest warte, można utworzyć typ danych typu "CoYoneda", np. 'Dane Serializowane a gdzie MkSerialized :: Serialize x => ByteString -> (x -> a) -> Serializowane a', które przechowuje ByteString i funkcja po deserializacji, która ma instancję 'Functor'. Ale oczywiście to pokonuje tutaj cel. – shachaf