为类型匹配定义Storable的受限子集 [英] Defining restricted subset of Storable for type match

查看:98
本文介绍了为类型匹配定义Storable的受限子集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码出现错误 - 我怀疑它与 dispatch 函数的类型签名有关,该函数返回一个 Vector 类型可存储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匹配类型`CChar'与`Int32'
期望类型:向量a
实际类型:向量Int32
在表达式中:x
在`dispatch'等式中:dispatch (I x)= x
失败,模块加载:无。

假设我的错误诊断正确,我在问这个问题。如果我的诊断不正确,我会很欣赏如何解决上述错误的指示。



  dispatch ::(Storable a)=> AList  - > SV.Vector a 

表示给我一个 AList ,我给你一个 SV.Vector a 用于任何 a 只要它是可存储的实例即可。那是不对的!对于任何给定的值,只有一个 a 您可以提供,选择它,而不是调用代码。如果您明确添加量词,问题可能会更容易看出:

  dispatch :: forall a。 (可存储的a)=> AList  - > SV.Vector a 

你真正想说的是给我一个 AList ,我给你一个 SV.Vector a 用于一些 a ,但我保证它会是 Storable 的实例。为此,我们需要一个存在类型:

  data SomeSVVector = forall a。 (可存储的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 出于派发 SomeSVVector vec的case dispatch x的结果 - > ...... 。然而,这可能并不是那么有用:因为存在可以包含一个带有任何实例 Storable 元素的向量,所以只有操作可以在内部数据上执行,这些操作是由 Storable 类提供的。如果你想要用户代码可以分析和分派类型的东西,你需要一个标记联合 - 这正是你的 AList 类型已经是



如果您确实想要使用存在路线,那么我建议将您自己的类型类定义为 Storable ,其中包含您可能想要对其中的值执行的所有操作。至少,您可能希望将 Integral 添加到 SomeSVVector 的约束中。






正如你在评论中提到的,如果你不介意 AList Int32 s和一个 AList CChar s具有不同的类型,你可以使用GADT:

  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

在这里, AList 本质上是 SV.Vector 的一个版本,它只适用于某些元素类型。然而, dispatch 并不是真的有用 - 没有真正的方法可以在返回到 AList 之后你用 dispatch 取出它,因为类型统一GADT模式匹配只能与显式模式匹配一​​起使用;你不能分辨出 dispatch 的结果是 SV.Vector Int32 还是 SV.Vector CChar 。就像

  dispatch ::(SV.Vector Int32  - > r) - > (SV.Vector CChar→> r)→> AList a  - > r 

会起作用,但这相当于您的原始标记上的模式匹配(并且比它更尴尬) union版本。



我认为没有合理的方法来定义有用的 dispatch ;我建议在你原来的 AList 定义上使用显式模式匹配。


I am getting error for the code below - I suspect it has to do with the type signature of dispatch function which returns a Vector of type Storable a. What is the simple way to update dispatch function type signature to do only Int32 and CChar in type signature:

{-#  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

Error in 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.

I am asking this question assuming my error diagnosis is correct. If my diagnosis is incorrect, I will appreciate pointers on how to fix the error above.

解决方案

The type signature

dispatch :: (Storable a) => AList -> SV.Vector a

says "give me an AList, and I'll give you an SV.Vector a for any a you want, so long as it's an instance of Storable". That's not right! For any given value, there's only one a you can supply, and you choose it, not the calling code. The problem might be easier to see if you explicitly add the quantifier:

dispatch :: forall a. (Storable a) => AList -> SV.Vector a

What you really want to say is "give me an AList, and I'l give you an SV.Vector a for some a that I choose, but I promise it'll be an instance of Storable". For this, we need an existential type:

data SomeSVVector = forall a. (Storable a) => SomeSVVector (SV.Vector a)

dispatch :: AList -> SomeSVVector
dispatch (I x) = SomeSVVector x
dispatch (S x) = SomeSVVector x

(You'll need {-# LANGUAGE ExistentialQuantification #-} for this.)

This gives SomeVVector the type:

SomeVVector :: (Storable a) => SV.Vector a -> SomeVVector

You can then take the SV.Vector out of the result of dispatch with case dispatch x of SomeSVVector vec -> .... However, this probably isn't all that useful: since the existential can contain a vector with elements of any instance of Storable, the only operations you'll be able to perform on the data inside are those offered by the Storable class. If you want something that user code can analyse and "dispatch" on the type of, you'll need a tagged union — which is exactly what your AList type already is.

If you do want to go down the existential route, then I would suggest defining your own typeclass as a subclass of Storable that contains all the operations you might want to perform on the values inside. At the very least, you'll probably want to add Integral to SomeSVVector's constraint.


As you mentioned in the comments, if you don't mind an AList of Int32s and an AList of CChars having different types, you can use a GADT:

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

Here, AList is essentially a version of SV.Vector that only works on certain element types. However, dispatch isn't really that useful — there's no real way to "get back in" to an AList after you take it out with dispatch, because the type unification GADT pattern-matching offers only works with explicit pattern-matching; you can't tell that the result of dispatch is either an SV.Vector Int32 or an SV.Vector CChar. Something like

dispatch :: (SV.Vector Int32 -> r) -> (SV.Vector CChar -> r) -> AList a -> r

would work, but that's equivalent to (and more awkward than) pattern-matching on your original tagged union version.

I don't think there's a reasonable way to define a useful dispatch; I would suggest using explicit pattern-matching on your original AList definition instead.

这篇关于为类型匹配定义Storable的受限子集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆