Сегодня я хотел исследовать, можно ли построить тип данных таким образом, чтобы он сохранял не данные типа своей сигнатуры типа, а другое его представление. Итак, вот моя попытка GADT, который имеет конструктор типа типа a
, но конструктор данных типа ByteString
.
{-# LANGUAGE GADTs #-}
import Data.ByteString.Char8
import Data.Serialize
data Serialized a where
MkSerialized :: (Serialize a) => ByteString -> Serialized a
Теперь я могу определить функцию decode'
следующим образом:
decode' :: (Serialize a) => Serialized a -> a
decode' (MkSerialized bs) = let Right r = (decode bs) in r
И это работает:
let s = MkSerialized (encode "test") :: Serialized String
print $ decode' s -- prints "test"
Моя проблема в том, что я хочу, чтобы Serialized
был экземпляром Functor
.
instance Functor Serialized where
fmap f (MkSerialized bs) = MkSerialized (encode (f (right (decode bs))))
where right (Right r) = r
Но я получаю ошибку (Serialize b) не может быть выведен. Как я могу ограничить экземпляр Functor, чтобы Serialize
применялся в fmap
?
Functor
не позволяет требовать ограничения на параметры типа. Есть ограниченный класс функтора,RFunctor
вrmonad
пакете. Может быть, ты сможешь это использовать. - person Daniel Fischer   schedule 18.06.2013Functor
, но я считаю своим долгом упомянуть: пожалуйста, не используйтеData.ByteString.Char8
по умолчанию! Это неработающий модуль, который поощряет неправильный код. Иногда его можно использовать, но ваш код также хорошо работает сData.ByteString
, что не способствует недопониманию Unicode. - person shachaf   schedule 18.06.2013CoYoneda
, напримерdata Serialized a where MkSerialized :: Serialize x => ByteString -> (x -> a) -> Serialized a
, который хранит ByteString и функцию пост-десериализации, и у которого есть экземплярFunctor
. Но, конечно, это противоречит цели. - person shachaf   schedule 18.06.2013