我收到以下代码的错误 - 我怀疑它与dispatch
函数的类型签名有关,它返回Vector
类型Storable a
。更新dispatch
函数类型签名以在类型签名中仅执行Int32
和CChar
的简单方法是什么:
{-# LANGUAGE BangPatterns #-}
import Data.Vector.Storable as SV
import Foreign.C.Types (CChar)
import GHC.Int (Int32)
data AList = I {-# UNPACK #-} !(SV.Vector Int32)
| S {-# UNPACK #-} !(SV.Vector CChar)
dispatch :: (Storable a) => AList -> SV.Vector a
dispatch (I x) = x
dispatch (S x) = x
ghci 7.4.1中的错误:
test.hs:11:18:
Couldn't match type `CChar' with `Int32'
Expected type: Vector a
Actual type: Vector Int32
In the expression: x
In an equation for `dispatch': dispatch (I x) = x
Failed, modules loaded: none.
假设我的错误诊断正确,我问这个问题。如果我的诊断不正确,我将非常感谢如何解决上述错误。
答案 0 :(得分:5)
类型签名
dispatch :: (Storable a) => AList -> SV.Vector a
说“给我一个AList
,我会给你一个SV.Vector a
任何 a
你想要的,只要它是一个实例Storable
”。那是不对的!对于任何给定的值,您只能提供一个 a
,您选择它,而不是调用代码。如果您明确添加量词,则可能更容易看到问题:
dispatch :: forall a. (Storable a) => AList -> SV.Vector a
你真正想说的是“给我一个AList
,我会给你一个SV.Vector a
我选择的 a
,但我保证它会成为Storable
的一个实例。为此,我们需要存在类型:
data SomeSVVector = forall a. (Storable a) => SomeSVVector (SV.Vector a)
dispatch :: AList -> SomeSVVector
dispatch (I x) = SomeSVVector x
dispatch (S x) = SomeSVVector x
(你需要{-# LANGUAGE ExistentialQuantification #-}
。)
这会给SomeVVector
类型:
SomeVVector :: (Storable a) => SV.Vector a -> SomeVVector
然后,您可以使用SV.Vector
从dispatch
的结果中取出case dispatch x of SomeSVVector vec -> ...
。但是,这可能不是那么有用:因为存在主义可以包含一个带有任何 Storable
实例元素的向量,所以仅操作能够对内部数据执行的是Storable
类提供的数据。如果你想要用户代码可以分析并“分派”类型的东西,你需要一个标记的联合 - 这正是你的AList
类型已经存在的。
如果您确实想要沿着存在路径前进,那么我建议您将自己的类型类定义为Storable
的子类,其中包含您可能希望对内部值执行的所有操作。至少,您可能希望将Integral
添加到SomeSVVector
的约束中。
正如您在评论中提到的,如果您不介意AList
Int32
和AList
CChar
个data AList a where
I :: {-# UNPACK #-} !(SV.Vector Int32) -> AList Int32
S :: {-# UNPACK #-} !(SV.Vector CChar) -> AList CChar
dispatch :: AList a -> SV.Vector a
dispatch (I x) = x
dispatch (S x) = x
具有不同的类型,您可以使用一个GADT:
AList
此处,SV.Vector
本质上是dispatch
的一个版本,仅适用于某些元素类型。但是,AList
并没有那么有用 - 在用dispatch
取出dispatch
之后,没有真正的方法可以“回到”SV.Vector Int32
,因为类型统一GADT模式 - 匹配商品仅适用于显式模式匹配;您无法确定SV.Vector CChar
的结果是dispatch :: (SV.Vector Int32 -> r) -> (SV.Vector CChar -> r) -> AList a -> r
还是dispatch
。像
AList
会起作用,但这相当于原始标记联合版本上的模式匹配(并且比其更尴尬)。
我认为没有合理的方法来定义有用的{{1}};我建议您在原始{{1}}定义中使用显式模式匹配。