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
says “give me an
AList, and I’ll give you anSV.Vector afor anyayou want, so long as it’s an instance ofStorable“. That’s not right! For any given value, there’s only oneayou can supply, and you choose it, not the calling code. The problem might be easier to see if you explicitly add the quantifier:What you really want to say is “give me an
AList, and I’l give you anSV.Vector afor someathat I choose, but I promise it’ll be an instance ofStorable“. For this, we need an existential type:(You’ll need
{-# LANGUAGE ExistentialQuantification #-}for this.)This gives
SomeVVectorthe type:You can then take the
SV.Vectorout of the result ofdispatchwithcase 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 ofStorable, the only operations you’ll be able to perform on the data inside are those offered by theStorableclass. 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 yourAListtype already is.If you do want to go down the existential route, then I would suggest defining your own typeclass as a subclass of
Storablethat contains all the operations you might want to perform on the values inside. At the very least, you’ll probably want to addIntegraltoSomeSVVector‘s constraint.As you mentioned in the comments, if you don’t mind an
AListofInt32s and anAListofCChars having different types, you can use a GADT:Here,
AListis essentially a version ofSV.Vectorthat only works on certain element types. However,dispatchisn’t really that useful — there’s no real way to “get back in” to anAListafter you take it out withdispatch, because the type unification GADT pattern-matching offers only works with explicit pattern-matching; you can’t tell that the result ofdispatchis either anSV.Vector Int32or anSV.Vector CChar. Something likewould 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 originalAListdefinition instead.