I have a datatype
newtype Zq q = Zq (IntType q)
where 'q' will be an instance of the class
class Foo a where
type IntType a
and 'IntType' is just the underlying representation (i.e. Int, Integral, etc) associated with 'q'.
I want to make Zq an instance of Data.Vector.Unbox. We are currently manually deriving Unbox using about 50 lines of trivial code as suggested in the link above. We will be making several different types 'Unbox' in our code, so writing 50 lines for each type is not appealing.
I found two alternatives here. One alternative is to use this package which uses Template Haskell to derive instances of Unbox. The TH code would look like:
derivingUnbox "Zq"
[d| instance (Foo q, U.Unbox (IntType q)) => Unbox' (ZqBasic q) (IntType q) |]
[| \ (Zq x) -> x |]
[| \ x -> Zq x |]
The problem is, I can't define instances using associated type synonyms (or can I??)
[A related question: Why does TypeSynonymInstances, an extension implied by FlexibleInstances, not allow associated type synonym instances? Is this somehow fundamentally a different beast?]
My current solution to that problem is to redefine Zq as
newtype Zq q i = Zq i
and then add the equality constraint
i~(IntType q)
in every instance involving (Zq q i), which isn't very elegant. My (working) Unbox derivation becomes
derivingUnbox "Zq"
[d| instance (U.Unbox i, i~IntType q, Foo q) => Unbox' (Zq q i) i |]
[| \ (Zq x) -> x |]
[| \ x -> Zq x |]
I feel like I should be able to accomplish this without resorting to explicitly exposing the type 'i'. All I've done is moved it from an associated type synonym to an explicit parameter with equality constraints. Why is this "fundamentally" a different (and apparently safer) approach? Is there some way I can avoid adding the type parameter 'i' and still get automatic Unbox derivation?
Extra type parameter aside, I'm having trouble using the TH package to derive Unbox for (Vector r), that is, I want to make an Unbox Vector of Unbox Vectors. My attempt is something like:
newtype Bar r = Bar (Vector r)
derivingUnbox "Bar"
[d| instance (Unbox r) => Unbox' (Bar r) (Vector r) |]
[| \ (Bar x) -> x |]
[| \ x -> Bar x |]
but I get (lots of) errors like:
`basicUnsafeFreeze` is not a (visible) method of class `Data.Vector.Generic.Base.Vector`
I'm not sure why it can't find this method, when it works just fine for my Zq type.
The second approach listed above is using the extension GeneralizedNewtypeDeriving. The biggest problem I see with this approach is that I have some actual Data (rather than Newtype) that I need to be Unbox. However, just using the extension, I should be able to write
newtype Zq q = Zq (IntType q) deriving (Unbox, M.MVector MVector, G.Vector Vector)
or at least
newtype Zq q i = Zq i deriving (Unbox, M.MVector MVector, G.Vector Vector)
The first leads to the errors:
No instance for (Unbox (IntType q)) arising from the `deriving` clause of a data type declaration
No instance for (M.MVector MVector (IntType q)) ""
No instance for (G.Vector Vector (IntType q)) ""
and the second gives:
No instance for (M.MVector MVector i) ""
No instance for (G.Vector U.Vector i) ""
I'm not sure why it can't derive these instances, as the post above leads me to believe it should be able to. Perhaps I could get away with using the associated type synonym with GeneralizedNewtypeDeriving? (This still (probably) doesn't solve my problem when I need to derive Unbox for 'data's.)
Thanks for your help!
Vector a
is not, and probably should never be, an instance ofUnbox
. Why do you think it would make sense?Unbox
types should generally be types that have a fixed-size representation in bytes, which is not the case forVector a
. The only possible alternative would be anUnbox
instance that secretly doesn't do any unboxing, and uses a normalData.Vector.Vector
, but I'm not sure there's any point to that. – Circumstantial