有一个简单的记录Column v a
,其中包含Vector
个Data.Vector
个v
,因此Vector.Unboxed
可以是Vector
,只有{{} 1}}等),它的名称和类型(简单的枚举类似ADT SupportedTypes
)。我希望能够使用binary
包序列化它。为此,我尝试在下面定义一个Binary
实例。
现在put
工作正常,但是当我尝试在get
函数中定义反序列化并想要根据{{返回的rawVector
设置特定类型时1}}(colType
当它U.Vector Int64
时,PInt
当它U.Vector Double
等时 - 我收到此错误消息:
无法将
匹配PDouble
类型与v
U.Vector
是由v
处的实例声明绑定的刚性类型变量:75:10预期类型:
src/Quark/Base/Column.hs
实际类型:
v a
错误。
是否有更好的方法来实现我的目标 - 根据U.Vector Int64
值反序列化不同类型的Vector
,或者我坚持为所有可能的{{1}定义colType
实例/原始类型组合?不应该是这样的......
Haskell有点新鲜,感谢任何帮助!谢谢!
Binary
更新感谢您下面的所有答案,一些不错的主意!很清楚,我想做的事情是不可能正面实现的 - 所以这就是我的答案。但其他建议的解决方案本身就是一个很好的解读,感谢一帮!
答案 0 :(得分:2)
您实际遇到的问题(或者如果您还没有,那就是您将会遇到的问题)是您正在尝试根据输入值确定结果类型。你不能那样做。完全没有。你可以巧妙地将结果类型锁定在一个盒子里并扔掉钥匙,这样外面的类型似乎是正常的,但是你不能用它做任何事情,因为你将这个类型锁在一个盒子里然后扔掉了键的。你可以使用GADT存储关于它的额外信息,并用类型类实例加载它,但即使这仍然不是一个好主意。
如果您只是为Column提供了两个构造函数来反映是否存在Int
s或Double
s的向量,那么您的生活将变得更加轻松。
但实际上,不要这样做。只需让自动派生的二进制实例为您解决任何可反序列化的值到您的向量中。
data Column a = ... deriving (Binary)
使用DeriveAnyClass
扩展程序,您可以派生任何具有Generic
实现(Binary
具有的)的类。然后,只需在需要时反序列化Column Double
或Column Int
。
答案 1 :(得分:2)
您真正想要表达的类型是
data Column v = Column (Either (v Int) (v Double))
但这种表述可能对您不满意。那么如何使用向量本身在构造函数的“顶层”编写此类型?
首先,在类型级别开始表示您的总和(Either Int Double
),而不是值级别:
data IsSupportedType a where
TInt :: IsSupportedType Int
TDouble :: IsSupportedType Double
从这里Column
实际上非常简单:
data Column v a = Column (IsSupportedType a) (v a)
但您可能希望a
存在量化,以便按您的需要使用它:
data Column v = forall a . Column (IsSupportedType a) (v a)
二进制实例如下:
instance (Binary (v Int), Binary (v Double)) => Binary (Column v) where
put (Column t v) = do
case t of
TInt -> put (0 :: Int) >> put v
TDouble -> put (1 :: Int) >> put v
get = do
t :: Int <- get
case t of
0 -> Column TInt <$> get
1 -> Column TDouble <$> get
请注意,此处Vector
没有固有的依赖性 - v
可能真的是什么。
答案 2 :(得分:1)
正如评论所说,你可以根本不在案例上,并且总是打电话
vec <- get
return Column {rawVector = vec, colName = nm, colType = pt}
这样可以正确完成您的类型签名。但请注意,colType
对您没有用处 - 您无法强制它对应于向量中的类型,因为它只存在于值级别。但这可能没问题,您可能只想从数据结构中删除colType
,因为您始终可以直接从a
中选择的具体类型Column v a
派生它。
事实上,Column
类型中的约束也没有做太多好处,我认为最好将其渲染为
data Column v a = Column {rawVector :: v a, colName :: Text}
现在,您可以在必要时在呼叫站点强制执行G.Vector
约束......