具有类型约束的GADT的Functor实例

Pha*_*rae 9 haskell functor type-constraints

今天我想研究是否有可能以这种方式构造数据类型,它不存储其类型签名类型的数据,而是它的另一种表示形式.所以,这是我对GADT的尝试,它具有类型的类型构造函数a,但是类型的数据构造函数ByteString.

{-# LANGUAGE GADTs #-}
import Data.ByteString.Char8
import Data.Serialize

data Serialized a where
    MkSerialized :: (Serialize a) => ByteString -> Serialized a
Run Code Online (Sandbox Code Playgroud)

现在我可以decode'通过以下方式定义一个函数:

decode' :: (Serialize a) => Serialized a -> a
decode' (MkSerialized bs) = let Right r = (decode bs) in r
Run Code Online (Sandbox Code Playgroud)

它有效:

let s = MkSerialized (encode "test") :: Serialized String
print $ decode' s     -- prints "test"
Run Code Online (Sandbox Code Playgroud)

我现在的问题是,我想Serialized成为一个实例Functor.

instance Functor Serialized where
    fmap f (MkSerialized bs) = MkSerialized (encode (f (right (decode bs))))
                               where right (Right r) = r
Run Code Online (Sandbox Code Playgroud)

但我得到的错误(序列化b)无法推断.如何约束F​​unctor实例,以便Serializefmap?中强制执行?

Rom*_*aka 6

您可以使用CoYoneda仿函数来完成此操作.

这个想法很简单:有一个额外的功能区域,您可以在其中累积您的fmap功能.解码值时,请应用该函数.

这是代码:

{-# LANGUAGE GADTs #-}
import Data.ByteString.Char8
import Data.Serialize

data Serialized a where
    MkSerialized
      :: (Serialize a)
      => ByteString -> (a -> b) -> Serialized b

decode' :: Serialized a -> a
decode' (MkSerialized bs f) = let Right r = decode bs in f r

instance Functor Serialized where
    fmap f (MkSerialized bs g) = MkSerialized bs (f . g)
Run Code Online (Sandbox Code Playgroud)

这也有利于自动融合多个fmaps而不是重复的解码和编码,就像你的情况一样.

  • 虽然这不是真正解决我的问题(因为我会喜欢`fmap`来重复去/编码),我会接受这个答案b/c我看到我原来的想法是不可能的,这是为约束GADT定义仿函数的最实用方法.此外,[有趣的读取GADT和Yoneda仿函数](http://www.haskellforall.com/2012/06/gadts.html). (2认同)