gpt4 book ai didi

haskell - 如何为此 GADT 编写序列化实例?

转载 作者:行者123 更新时间:2023-12-04 02:28:07 25 4
gpt4 key购买 nike

下面是一个尝试实现 Serialize 的模块例如一个简单的 GADT。不幸的是 get Reorder 的实现构造函数提示没有 Ixed a约束。有什么方法,漂亮或丑陋,来实现这个?我无法添加 Ixed a到实例上下文,因为 Update构造函数需要为不满足此约束的值工作。

{-# LANGUAGE GADTs #-}

import Control.Lens (Index, Ixed)
import Data.Serialize

-- | Two different ways of updating a value - replacing it completely or,
-- if it is an instance of Ixed, re-ordering it.
data Op a where
Update :: Serialize a => a -> Op a
Reorder :: (Ixed a, Serialize (Index a)) => [Index a] -> Op a

instance Serialize a => Serialize (Op a) where
put (Update a) = putWord8 1 >> put a
put (Reorder ks) = putWord8 2 >> put ks
get = do
i <- getWord8
case i of
1 -> Update <$> get
2 -> Reorder <$> get
_ -> error "instance Serialize (Op a) - corrupt data"

附录:对此的一种简化可能是使类型变量 a幻像类型,因此 Op看起来像这样:
data Op a where
Update :: Serialize a => ByteString -> Op a
Reorder :: (Ixed a, Serialize (Index a)) => [ByteString] -> Op a
然后可以使用该类型正确解码字节字符串。不确定这是否有帮助

最佳答案

通常,您要尝试做的事情是不可能的。本质上,您试图让 GHC 推断 Ixed aSerialize (Index a)仅给出 Serialize a .当然,这可能适用于您想到的任何用例,但它通常不起作用,这就是 GHC 拒绝您的实例的原因。
我说“一般来说不可能”,因为如果你指定你关心的类型,那么它绝对是可能的。这意味着您必须列出所有可以从 Reorder 序列化的类型。 ,但这真的和你能得到的一样好。
有多种方法可以做到这一点,但我认为最简单的方法是使用 constraints包以在 Dict 中捕获您想要的内容.您首先要定义:

class MaybeSerializeIndexed a where
canSerializeIndex :: Maybe (Dict (Ixed a, Serialize (Index a)))
default canSerializeIndex :: (Ixed a, Serialize (Index a)) -> Maybe (Dict (Ixed a, Serialize (Index a)))
canSerializeIndex = Just Dict
默认签名(需要 DefaultSignatures 杂注)是让您的生活变得简单的关键,因为这意味着您可以使用简单的一行来列出您关心的类型,如下所示:
instance Serialize a => MaybeSerializeIndexed [a]
instance Serialize k => MaybeSerializeIndexed (Map k a)
除此之外,您还可以创建一个重叠实例来处理不支持 Reorder 的类型。 :
instance {-# OVERLAPPABLE #-} MaybeSerializeIndexed a where
canSerializeIndex = Nothing
有了这个机器,您可以编写您的实例:
instance (MaybeSerializeIndexed a, Serialize a) => Serialize (Op a) where
put (Update a) = putWord8 1 >> put a
put (Reorder ks) = putWord8 2 >> put ks
get = do
i <- getWord8
case (i, canSerializeIndex @a) of
(1, _) -> Update <$> get
(2, Just Dict) -> Reorder <$> get
_ -> error "instance Serialize (Op a) - corrupt data"
请注意,添加 MaybeSerializeIndexed a对您的实例的约束实际上并不是什么大问题,因为每种类型都有一个实例。这也意味着,如果您在系统中添加新类型而不添加 MaybeSerializeIndexed例如,当你尝试反序列化它时,你不会得到类型错误——你只会得到一个运行时错误。例如,如果您添加一个新类型 Foo你知道的地方 Ixed FooSerialize (Index Foo)但你不加 instance MaybeSerializeIndexed Foo ,那么如果您编写一个尝试 get 的程序,您将不会收到类型错误。一个 Foo值,但运行时会出现运行时错误。

关于haskell - 如何为此 GADT 编写序列化实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65941212/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com