類型簽名
dispatch :: (Storable a) => AList -> SV.Vector a
說:「給我一個AList
,我給你任何a
你想要一個SV.Vector a
,只要它是Storable
的實例」。那是不對的!對於任何給定的值,只有一個a
你可以提供,而你選擇它,而不是調用代碼。這個問題可能會更容易看到,如果你明確添加量詞:
dispatch :: forall a. (Storable a) => AList -> SV.Vector a
你真正想說的是「給我一個AList
和I'l給你的SV.Vector a
一些a
我選擇,但我保證它會成爲Storable
的實例「。對於這一點,我們需要一個存在類型:(你需要{-# LANGUAGE ExistentialQuantification #-}
此)
data SomeSVVector = forall a. (Storable a) => SomeSVVector (SV.Vector a)
dispatch :: AList -> SomeSVVector
dispatch (I x) = SomeSVVector x
dispatch (S x) = SomeSVVector x
這給SomeVVector
類型:
SomeVVector :: (Storable a) => SV.Vector a -> SomeVVector
您可以再取SV.Vector
在dispatch
與case dispatch x of SomeSVVector vec -> ...
的結果中。然而,這可能並不是那麼有用:因爲存在可以包含一個向量,其中包含的任何實例的Storable
,您可以對其中的數據執行的操作是Storable
類。如果你想要一些用戶代碼可以分析和「派發」的類型,你需要一個標記聯盟 - 這正是你的AList
類型已經是。
如果您確實想要走下存在路線,那麼我會建議將您自己的類型類定義爲Storable
的子類,其中包含您可能希望對其中的值執行的所有操作。至少,您可能需要將Integral
添加到SomeSVVector
的約束。
當您在評論中提到,如果你不介意Int32
S的AList
和的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
並不真正有用 - 因爲類型統一GADT模式匹配只能與顯式模式匹配一起使用,所以在您將它帶出dispatch
後,沒有辦法「回到」AList
;你不能說dispatch
的結果是SV.Vector Int32
或SV.Vector CChar
。像
dispatch :: (SV.Vector Int32 -> r) -> (SV.Vector CChar -> r) -> AList a -> r
東西會的工作,但是這等同於(且超過彆扭)的模式匹配您的原始標籤聯合版本。
我不認爲有一個合理的方法來定義有用的dispatch
;我建議您在原始AList
定義上使用顯式模式匹配。
謝謝。這正是我所期待的。我知道我寫的是不對的。現在,我已經更好地瞭解了潛在類型:)最後,我將根據案例進行調度以轉換爲另一種類型。這就是爲什麼我爲AList添加了標籤。 – Sal 2012-02-07 15:05:09
剛剛意識到GADT可能是另一種方式來做到這一點。基本上,派遣可以有一個類型簽名:(Storable a)=> AList(SV.Vector a) - > SV.Vector a。使用GADT定義(AList a)後。我只是嘗試了一個例子,它似乎做了匹配類型的訣竅。如果您認爲這有效,如果您可以使用GADT替代方式編輯您的答案,我會很感激。一個示例代碼在這裏:http://hpaste.org/57584 – Sal 2012-02-07 16:34:21
不幸的是,它可能不會做你想要的;我已經用解釋擴展了我的答案。順便說一句,正如我的回答所示,'dispatch'上的'Storable'約束沒有任何作用,並且可以直接在元素類型上參數化'AList',而不是向量類型。 – ehird 2012-02-07 16:58:35