2012-02-07 9 views
3

以下のコードでエラーが発生します。タイプStorable aVectorを返すdispatch関数の型シグニチャと関係があると思われます。私のエラーを想定しタイプマッチのためにStorableの限定サブセットを定義する

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. 

私はこの質問をしています:

{-# 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に:のみInt32CChar型シグネチャに行うためにdispatch関数の型シグネチャを更新するための簡単な方法は何ですか診断は正しい。私の診断が間違っている場合、私は上記のエラーを解決する方法のポイントを感謝します。

答えて

5

型シグネチャ

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

は「私にAListを与える、と私は、それがStorableのインスタンスだとして、あなたがしたいためSV.Vector a任意のaを与えるでしょう」と言います。それは正しくない!任意の値に対して、のいずれか1つだけaを指定できます。を選択してください。呼び出しコードではありません。問題を明示的数量詞を追加するかどうかを確認する方が簡単かもしれません:

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

あなたが本当に言いたいことは、私にAListを与え、そしてI'lはあなたに私が選ぶ、一部のaためSV.Vector aを与える」でありますしかし、私はそれがStorableのインスタンスになると約束します。 "あなたはその後、取ることができ

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

:これはSomeVVectorタイプを与える

(あなたはこのため{-# 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 

:このために、我々は実存タイプを必要としますdispatchの結果のうちSV.Vectorcase dispatch x of SomeSVVector vec -> ...である。しかし、これはすべて役に立つわけではありません:実在性には、の任意のベクトルのインスタンスがStorableのため、の操作は、Storableクラス。ユーザーコードが分析でき、タイプに「ディスパッチ」できるものが必要な場合は、タグ付きのユニオンが必要です。これはまさにあなたのタイプのAListです。

実在するルートを下りたい場合は、内部の値に対して実行したいすべての操作を含むStorableのサブクラスとして独自の型クラスを定義することをお勧めします。最低でも、おそらくIntegralSomeSVVectorの制約に追加したいと思うでしょう。


あなたはコメントで述べたように、あなたがAListInt32のSと種類が異なる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

感謝。それはまさに私が探していたものです。私が書いたことは正しいとは思わない。今、私はexitentialの型についてもっと学びました:)結局​​、別の型に変換するためにケースに基づいてディスパッチを行います。だから私はAListのための組合にタグをつけたのです。 – Sal

+0

ちょうど実現したGADTは別の方法かもしれません。基本的に、ディスパッチにはタイプシグネチャがあります。(Storable a)=> AList(SV.Vector a) - > SV.Vector a。 GADTを使用して(AList a)を定義した後。私は例を試したところ、マッチするタイプのトリックをするようです。これがうまくいくと思うのであれば、上記の回答をGADTの別の方法でも編集できれば幸いです。サンプルコードはこちら:http://hpaste.org/57584 – Sal

+0

残念ながら、おそらくあなたが望むことはしません。私は解説を拡大して説明しました。ちなみに、私の答えに示すように、dispatch' 'に' Storable'制約は何もしていない、とあなたはAList'は直接要素にベクトルのタイプではなく、入力 'parametriseことができます。 – ehird

関連する問題