Haskell:获取Get单子并返回无限类型上的多态性

Haskell:获取Get单子并返回无限类型上的多态性,haskell,serialization,Haskell,Serialization,如果以下是基于我的误解,我提前道歉。我在任何地方都找不到我需要的答案 我正在实现一个从文件中读取序列化对象的程序,在整个过程中都使用惰性计算。我首先将该文件作为一个Lazy ByteString读入,然后使用Get Monad对其进行解析。在文件中,有一个点存储类型描述符,另一个点存储数据。类型描述符告诉我如何解释数据以及数据最终的类型,并且该类型可以采用嵌套形式;Double或[[Word8]]是两种可能性 现在,我提出了这样做的想法(听起来非常优雅):如果该方法(解析类型描述符)创建了一个G

如果以下是基于我的误解,我提前道歉。我在任何地方都找不到我需要的答案

我正在实现一个从文件中读取序列化对象的程序,在整个过程中都使用惰性计算。我首先将该文件作为一个Lazy ByteString读入,然后使用Get Monad对其进行解析。在文件中,有一个点存储类型描述符,另一个点存储数据。类型描述符告诉我如何解释数据以及数据最终的类型,并且该类型可以采用嵌套形式;Double或[[Word8]]是两种可能性

现在,我提出了这样做的想法(听起来非常优雅):如果该方法(解析类型描述符)创建了一个Get Monad(但不运行),然后可以使用保存数据的ByteString运行该方法,该怎么办

这就需要这样一种方法:

parseTypeDescriptor :: Get (Get a)
其中,a与描述符描述的类型相同(意味着它可以采用嵌套形式)。下面是目前代码的一些部分:

parseTypeDescriptor :: Get (Get a)
-- first part of the type descriptor is an id (Word8) that implies a type
parseTypeDescriptor = getWord8 >>= go
   where go 0 = return getWord8
         go 1 = return getWord16be
         go 2 = return getWord32be
                 ...
         -- id 5 indicates that the type is an array
         -- this means two more values are coming;
         -- the first indicates the array's length, the second its type
         go 5 = do n      <- getWord8
                   action <- parseTypeDescriptor
                   return $ -- TODO --
parseTypeDescriptor::Get(Get a)
--类型描述符的第一部分是一个表示类型的id(Word8)
parseTypeDescriptor=getWord8>>=go
其中go 0=返回getWord8
go 1=返回getWord16be
go 2=返回getWord32be
...
--ID5表示该类型是数组
--这意味着还有两个价值观即将到来;
--第一个表示数组的长度,第二个表示数组的类型

go 5=do n您并没有真正返回多态性(普遍量化)的内容–事实上,您总是返回一个具体的类型
Get a
,但它只会在运行时决定是哪个类型。这就是所谓的。Haskell 98没有这样的功能,但您可以使用广义代数数据类型:

{-# LANGUAGE GADTs #-}
data GetSomething where
   GetSomething :: Get a -> GetSomething

parseTypeDescriptor :: Get GetSomething
-- first part of the type descriptor is an id (Word8) that implies a type
parseTypeDescriptor = getWord8 >>= go
   where go 0 = return $ GetSomething getWord8
         go 1 = return $ GetSomething getWord16be
         go 2 = return $ GetSomething getWord32be
到目前为止还不错。。。问题是,使用
GetSomething
,实际上没有什么有用的东西,因为无法知道它实际生成的是什么类型(它隐藏在GADT中)。有一些方法可以克服这一点–例如,如果所有解析的类型都属于一个公共类型类,则可以将其添加为约束:

data GetSomething where
   GetSomething :: CommonClass a => Get a -> GetSomething
这样,即使不知道确切的类型,您也可以解析值并对其进行处理

然而,这可能不是最好的方法:基本上,您必须始终跟踪丢失的类型信息,并四处黑客攻击,才能完成工作。在Haskell中,存在主义被认为有点反模式

更好的解决方案可能是将类型放在清晰的替代数据结构中:

data GetSomething
   = GetW8 (Get Word8)
   | GetW16 (Get Word16)
   | ...
   | GetList [GetSomething]

然后,您可以简单地进行模式匹配,找出您拥有的特定类型,并且由于支持的类型列表是有限的,因此您可以确保不会因为实际不支持某个类型而遇到问题。

我担心正确的类型应该是
Get(exists a.Get a)
,使用存在性而不是通用的量化(现在让我们忽略预测性问题…)。这也意味着这个解析器不会提供任何关于输出类型的静态保证,因此它的结果实际上是不可用的。我会让解析器返回大量的内容,或者最坏的情况是返回
Dynamic
。因此,这似乎是不可行的。除了其他人指出的关于存在论的细节外,你的直觉认为
Get(Get a)
给了你上下文敏感性是正确的。这基本上是因为
Monad
配备了
join::m(ma)->ma
Monad
描述了可以依赖于先前结果的计算,而不像
Applicative
data GetSomething
   = GetW8 (Get Word8)
   | GetW16 (Get Word16)
   | ...
   | GetList [GetSomething]