<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><span class="">I am trying to create a data type that is an vector of values, but internally uses an unboxed vector when possible and a boxed array otherwise. If this already exists, let me know. For example, any easily unboxed type is stored in an unboxed array, but also any type that is a product type of only easily unboxed types like (Int, Int) is stored in multiple unboxed arrays. I don’t think there is a smart way of doing this for sum types, so those are stored in boxed arrays.<br class=""><br class=""></span>I’m trying to create a typeclass<div class=""><span class=""><br class=""></span><div class=""><span style="font-size: 14px;" class=""><font face="Iosevka" class=""><div class="">class VectorElement a where</div><div class=""> data Vector a</div><div class=""> replicate :: Int -> a -> Vector a</div><div class=""> length :: Vector a -> Int</div></font></span><div class=""><span class=""><br class="">to represent things that can be stored in Vectors. I can then implement it for specific types that I know can be stored in unboxed vectors:<br class=""><div class=""><br class=""></div></span><div class=""><span class=""><font face="Iosevka" style="font-size: 14px;" class="">instance VectorElement Int where<br class=""> newtype Vector Int = VectorInt (U.Vector Int)<br class=""> deriving Show<br class=""> replicate len x = VectorInt $ U.replicate len x<br class=""> length (VectorInt v) = U.length v</font><br class=""><br class=""></span></div><span class=""><div class=""><span class="">I also want to automatically derive instances of this class for other types using the Generic typeclass. Ideally these instances would be the most efficient possible, so that for example the instance for (Int, Int) used two unboxed arrays but the instance for Maybe Int uses a boxed array. To that end I created another typeclass and wrote instances for the Generic data constructors:<br class=""><br class=""><div class=""><font face="Iosevka" style="font-size: 14px;" class="">class VectorElementG (r :: * -> *) where</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> data VectorG r</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> replicateG :: Int -> r a -> VectorG r</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> lengthG :: VectorG r -> Int</font></div><div class=""><br class=""></div><div class=""><font face="Iosevka" style="font-size: 14px;" class="">instance VectorElementG V1 where</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> data VectorG V1</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> replicateG = undefined</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> lengthG = undefined</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""><br class=""></font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class="">instance VectorElementG U1 where</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> newtype VectorG U1 = VectorGUnit Int</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> replicateG i U1 = VectorGUnit i</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> lengthG (VectorGUnit i) = i</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""><br class=""></font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class="">instance VectorElement a => VectorElementG (K1 i a) where</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> newtype VectorG (K1 i a) = VectorGK (Vector a)</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> replicateG i (K1 x) = VectorGK $ replicate i x</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> lengthG (VectorGK v) = length v</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""><br class=""></font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class="">instance (VectorElementG r1, VectorElementG r2) => VectorElementG (r1 :*: r2) where</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> data VectorG (r1 :*: r2) = VectorGProd (VectorG r1) (VectorG r2)</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> replicateG i (a :*: b) = VectorGProd (replicateG i a) (replicateG i b)</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> lengthG (VectorGProd v _) = lengthG v</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""><br class=""></font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class="">instance VectorElement ((r1 :+: r2) p) where</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> newtype Vector ((r1 :+: r2) p) = VectorSum (V.Vector ((r1 :+: r2) p))</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> replicate i x = VectorSum $ V.replicate i x</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> length (VectorSum v) = V.length v</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""><br class=""></font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class="">instance VectorElementG f => VectorElementG (M1 i c f) where</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> newtype VectorG (M1 i c f) = VectorGMeta (VectorG f)</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> replicateG i (M1 f) = VectorGMeta $ replicateG i f</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> lengthG (VectorGMeta v) = lengthG v</font></div><div class=""><br class=""></div><br class="">I’m not sure if these are correct, especially the one for :+:. I want basically base cases to be any type that already has an instance of VectorElement or a sum type which is automatically boxed, and the recursive case to basically just use parallel vectors for product types.</span></div></span><span class=""><div class=""><span class=""><br class=""></span></div></span><div class=""><span class="">I think this sort of worked insofar as it allowed me to write an instance for tuples:</span></div><div class=""><span class=""><br class=""></span></div><div class=""><span class=""><div class=""><font face="Iosevka" style="font-size: 14px;" class="">instance (VectorElement a, VectorElement b) => VectorElement (a,b) where</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> newtype Vector (a, b) = VectorTuple (VectorG (Rep (a, b)))</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> replicate i x = VectorTuple $ replicateG i (from x)</font></div><div class=""><font face="Iosevka" style="font-size: 14px;" class=""> length (VectorTuple v) = lengthG v</font></div><div class=""><span class=""><br class=""></span></div>Ideally, however, the compiler would automatically derive this instance using the Generic instance. Is there a way to do that also?</span></div><div class=""><span class=""><br class=""></span></div><div class=""><span class="">I would welcome any thoughts on this entire idea and approach.</span></div><div class=""><span class=""><br class=""></span></div><div class=""><span class="">Thanks,</span></div><div class=""><span class="">Jake Waksbaum</span></div></div></div></div></body></html>