2012-02-07 20 views
3

我得到以下代碼的錯誤 - 我懷疑它與dispatch函數的類型簽名有關,該函數返回Storable a類型的Vector。有什麼簡單的方法來更新dispatch函數類型簽名只做Int32CChar式簽名:定義類型匹配的可存儲的限制子集

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

我問這個問題,假設我的錯誤診斷是正確的。如果我的診斷不正確,我將很高興指出如何解決上述錯誤。

回答

5

類型簽名

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.Vectordispatchcase dispatch x of SomeSVVector vec -> ...的結果中。然而,這可能並不是那麼有用:因爲存在可以包含一個向量,其中包含的任何實例的Storable,您可以對其中的數據執行的操作是Storable類。如果你想要一些用戶代碼可以分析和「派發」的類型,你需要一個標記聯盟 - 這正是你的AList類型已經是。

如果您確實想要走下存在路線,那麼我會建議將您自己的類型類定義爲Storable的子類,其中包含您可能希望對其中的值執行的所有操作。至少,您可能需要將Integral添加到SomeSVVector的約束。


當您在評論中提到,如果你不介意Int32 S的AList和的AListCChar具有不同類型的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 Int32SV.Vector CChar。像

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

東西會的工作,但是這等同於(且超過彆扭)的模式匹配您的原始標籤聯合版本。

我不認爲有一個合理的方法來定義有用的dispatch;我建議您在原始AList定義上使用顯式模式匹配。

+0

謝謝。這正是我所期待的。我知道我寫的是不對的。現在,我已經更好地瞭解了潛在類型:)最後,我將根據案例進行調度以轉換爲另一種類型。這就是爲什麼我爲AList添加了標籤。 – Sal 2012-02-07 15:05:09

+0

剛剛意識到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

+0

不幸的是,它可能不會做你想要的;我已經用解釋擴展了我的答案。順便說一句,正如我的回答所示,'dispatch'上的'Storable'約束沒有任何作用,並且可以直接在元素類型上參數化'AList',而不是向量類型。 – ehird 2012-02-07 16:58:35

相關問題