diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,50 @@
+# Changelog
+
+## [0.3] - 2018-02-18
+
+### Added
+
+- GHC 8.2.x support
+
+### Changed
+
+- `Data.Vec3.Unboxed.Contiguous` is now again `Data.Vec3.Unboxed`.
+  `UVec3` was merged with `SVec3` and renamed to `CVec3`.
+
+- `Data.Vec3.Unboxed` is now `Data.Vec3.Tupled` and renamed to
+  `TVec3`.
+
+- Benchmarks were reorganized to work well with Criterion group
+  coloring
+
+### Removed
+
+- `SVec3` (merged into `CVec3`)
+
+## [0.2] - 2016-10-14
+
+### Added
+
+- Tests
+
+### Changed
+
+- `Data.Vec3.Unboxed` is now `Data.Vec3.Unboxed.Contiguous`
+
+- `Data.Vec3.TUnboxed` is now `Data.Vec3.Unboxed` and uses
+  [vector-th-unbox][] to generate Unbox instance
+
+## [0.1.0.1] - 2012-12-13
+
+### Changed
+
+- Benchmark is now an actual Cabal-friendly benchmark
+
+## [0.1.0.0] - 2012-12-05
+
+[0.3]:     https://github.com/dzhus/simple-vec3/compare/0.2...0.3
+[0.2]:     https://github.com/dzhus/simple-vec3/compare/0.1.0.1...0.2
+[0.1.0.1]: https://github.com/dzhus/simple-vec3/compare/0.1.0.0...0.1.0.1
+[0.1.0.0]: https://github.com/dzhus/simple-vec3/tree/0.1.0.0
+
+[vector-th-unbox]: https://hackage.haskell.org/package/vector-th-unbox
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2012, Dmitry Dzhus
+Copyright (c) 2012-2018, Dmitry Dzhus
 
 All rights reserved.
 
diff --git a/benchmark/Benchmark.hs b/benchmark/Benchmark.hs
--- a/benchmark/Benchmark.hs
+++ b/benchmark/Benchmark.hs
@@ -7,7 +7,6 @@
 import Data.Vector.Unboxed as VU
 
 import Data.Vec3
-import qualified Data.Vec3.Unboxed.Contiguous as C
 
 
 oXYZ :: (Double, Double, Double)
@@ -19,11 +18,7 @@
 
 
 n :: Int
-n = 1000000
-
-
-bigN :: Int
-bigN = n * 10
+n = 10000000
 
 
 -- Access to whole elements
@@ -50,86 +45,46 @@
     dotM' e1 e2 = dotM e1 e2 m
 
 
--- Note that source arrays are not forced in test functions.
-
-tv :: VU.Vector UVec3
-tv = VG.replicate n $ fromXYZ oXYZ
-
-
-cv :: VU.Vector C.UVec3
-cv = VG.replicate n $ fromXYZ oXYZ
-
-
-sv :: VS.Vector SVec3
-sv = VG.replicate n $ fromXYZ oXYZ
-
-
-tv' :: VU.Vector UVec3
-tv' = VG.replicate n $ fromXYZ oXYZ'
-
-
-cv' :: VU.Vector C.UVec3
-cv' = VG.replicate n $ fromXYZ oXYZ'
+testNormalize :: (Vec3 a, VG.Vector v a) => v a -> Benchmarkable
+testNormalize = whnf (VG.map normalize)
 
 
-sv' :: VS.Vector SVec3
-sv' = VG.replicate n $ fromXYZ oXYZ'
-
+-- Note that source arrays are not forced in test functions.
 
-bsv :: VS.Vector SVec3
-bsv = VG.replicate bigN $ fromXYZ oXYZ
+csv :: VS.Vector CVec3
+csv = VG.replicate n $ fromXYZ oXYZ
 
 
-bcv :: VU.Vector C.UVec3
-bcv = VG.replicate bigN $ fromXYZ oXYZ
+cuv :: VU.Vector CVec3
+cuv = VG.replicate n $ fromXYZ oXYZ
 
 
-btv :: VU.Vector UVec3
-btv = VG.replicate bigN $ fromXYZ oXYZ
+tv :: VU.Vector TVec3
+tv = VG.replicate n $ fromXYZ oXYZ
 
 
-bsv' :: VS.Vector SVec3
-bsv' = VG.replicate bigN $ fromXYZ oXYZ'
+csv' :: VS.Vector CVec3
+csv' = VG.replicate n $ fromXYZ oXYZ'
 
 
-bcv' :: VU.Vector C.UVec3
-bcv' = VG.replicate bigN $ fromXYZ oXYZ'
+cuv' :: VU.Vector CVec3
+cuv' = VG.replicate n $ fromXYZ oXYZ'
 
 
-btv' :: VU.Vector UVec3
-btv' = VG.replicate bigN $ fromXYZ oXYZ'
+tv' :: VU.Vector TVec3
+tv' = VG.replicate n $ fromXYZ oXYZ'
 
 
 main :: IO ()
 main = defaultMain
-       [ bgroup "zipWith"
-                    [ bench "SVec/Storable"           $ testWhole sv sv'
-                    , bench "UVec/Unboxed"            $ testWhole tv tv'
-                    , bench "UVec/Unboxed/Contiguous" $ testWhole cv cv'
-                    ]
-       , bgroup "zipWith-by-x"
-                    [ bench "SVec/Storable"           $ testComp sv sv'
-                    , bench "UVec/Unboxed"            $ testComp tv tv'
-                    , bench "UVec/Unboxed/Contiguous" $ testComp cv cv'
-                    ]
-       , bgroup "zipWith-dotM"
-                    [ bench "SVec/Storable"           $ testDotM sv sv'
-                    , bench "UVec/Unboxed"            $ testDotM tv tv'
-                    , bench "UVec/Unboxed/Contiguous" $ testDotM cv cv'
-                    ]
-       , bgroup "zipWith 10M"
-                    [ bench "SVec/Storable"           $ testWhole bsv bsv'
-                    , bench "UVec/Unboxed"            $ testWhole btv btv'
-                    , bench "UVec/Unboxed/Contiguous" $ testWhole bcv bcv'
-                    ]
-       , bgroup "zipWith-by-x 10M"
-                    [ bench "SVec/Storable"           $ testComp bsv bsv'
-                    , bench "UVec/Unboxed"            $ testComp btv btv'
-                    , bench "UVec/Unboxed/Contiguous" $ testComp bcv bcv'
-                    ]
-       , bgroup "zipWith-dotM 10M"
-                    [ bench "SVec/Storable"           $ testDotM bsv bsv'
-                    , bench "UVec/Unboxed"            $ testDotM btv btv'
-                    , bench "UVec/Unboxed/Contiguous" $ testDotM bcv bcv'
-                    ]
+       [ bgroup "CVec3/Storable" $ mkGroup csv csv'
+       , bgroup "CVec3/Unboxed"  $ mkGroup cuv cuv'
+       , bgroup "TVec3/Unboxed"  $ mkGroup tv tv'
        ]
+  where
+    mkGroup v1 v2 =
+      [ bench "zipWith-add"      $ testWhole v1 v2
+      , bench "zipWith-by-x-add" $ testComp v1 v2
+      , bench "zipWith-dotM"     $ testDotM v1 v2
+      , bench "normalize"        $ testNormalize v1
+      ]
diff --git a/simple-vec3.cabal b/simple-vec3.cabal
--- a/simple-vec3.cabal
+++ b/simple-vec3.cabal
@@ -1,17 +1,19 @@
 name: simple-vec3
-version: 0.2
+version: 0.3
 cabal-version: >=1.10
 build-type: Simple
 license: BSD3
 license-file: LICENSE
-maintainer: <dima@dzhus.org>
+maintainer: dima@dzhus.org
 homepage: https://github.com/dzhus/simple-vec3#readme
 bug-reports: https://github.com/dzhus/simple-vec3/issues
 synopsis: Three-dimensional vectors of doubles with basic operations
 description:
-    A class of 3-vectors with a set of basic methods for geometry operations on vectors and an associated matrix type. Instances are provided for use with "Data.Vector.Unboxed" and "Data.Vector.Storable" as container types.
+    Simple three-dimensional vectors of doubles with basic vector and matrix operations, supporting "Data.Vector.Unboxed" and "Data.Vector.Storable".
 category: Math, Numerical
 author: Dmitry Dzhus
+extra-source-files:
+    CHANGELOG.md
 
 source-repository head
     type: git
@@ -21,43 +23,47 @@
     exposed-modules:
         Data.Vec3
         Data.Vec3.Class
-        Data.Vec3.Unboxed
-        Data.Vec3.Unboxed.Contiguous
     build-depends:
-        base >=4.9.0.0 && <5,
-        QuickCheck >=2.8.2,
-        vector >=0.11.0.0,
-        vector-th-unbox >=0.2.1.6
+        QuickCheck <2.11,
+        base <5,
+        vector <0.13,
+        vector-th-unbox <0.3
     default-language: Haskell2010
     hs-source-dirs: src
-    ghc-options: -Wall
+    other-modules:
+        Data.Vec3.Tupled
+    ghc-options: -Wall -Wcompat -O2
 
-test-suite pythia-recommender-test
+test-suite  simple-vec3-test
     type: exitcode-stdio-1.0
     main-is: Tests.hs
     build-depends:
-        base >=4.9.0.0 && <5,
-        QuickCheck >=2.8.2,
-        vector >=0.11.0.0,
-        vector-th-unbox >=0.2.1.6,
-        simple-vec3 >=0.2,
-        tasty >=0.11.0.4,
-        tasty-quickcheck >=0.8.4,
-        tasty-th >=0.1.4
+        QuickCheck <2.11,
+        base <5,
+        simple-vec3 -any,
+        tasty <0.13,
+        tasty-quickcheck <0.10,
+        tasty-th <0.2,
+        vector <0.13,
+        vector-th-unbox <0.3
     default-language: Haskell2010
     hs-source-dirs: tests
-    ghc-options: -Wall
+    other-modules:
+        Paths_simple_vec3
+    ghc-options: -Wall -Wcompat -O2
 
-benchmark simple-vec3-benchmark
+benchmark  simple-vec3-benchmark
     type: exitcode-stdio-1.0
     main-is: Benchmark.hs
     build-depends:
-        base >=4.9.0.0 && <5,
-        QuickCheck >=2.8.2,
-        vector >=0.11.0.0,
-        vector-th-unbox >=0.2.1.6,
-        criterion >=1.1.1.0,
-        simple-vec3 >=0.2
+        QuickCheck <2.11,
+        base <5,
+        criterion <1.3,
+        simple-vec3 -any,
+        vector <0.13,
+        vector-th-unbox <0.3
     default-language: Haskell2010
     hs-source-dirs: benchmark
-    ghc-options: -Wall
+    other-modules:
+        Paths_simple_vec3
+    ghc-options: -Wall -Wcompat -O2
diff --git a/src/Data/Vec3.hs b/src/Data/Vec3.hs
--- a/src/Data/Vec3.hs
+++ b/src/Data/Vec3.hs
@@ -5,43 +5,145 @@
 
 'Vec3' class and implementations.
 
+The package provides two different implementations for 'Vec3' type
+class, which differ in storage scheme. Benchmarks are included for
+both. You most likely want to use 'CVec3' which is based on contiguous
+storage scheme and offers the best performance.
+
 -}
 
 module Data.Vec3
     ( Vec3(..)
-    , SVec3(..)
-    , UVec3(..)
+    , CVec3(..)
+    , TVec3(..)
     )
 
 where
 
-import Prelude hiding (reverse)
+import Control.Monad
 
 import Foreign
 import Foreign.C.Types
 
+import Data.Vector.Unboxed as VU
+import Data.Vector.Generic as VG
+import Data.Vector.Generic.Mutable as VGM
+import Test.QuickCheck
+
 import Data.Vec3.Class
-import Data.Vec3.Unboxed
 
-import Test.QuickCheck
+import Data.Vec3.Tupled
 
 
--- | 'Vec3' implementation with 'Foreign.Storable.Storable' instance
--- based on a single contiguous array storage scheme, suitable for use
--- with "Data.Vector.Storable".
---
--- 'Unbox' instance provides the required index transformations.
+-- | 'Vec3' implementation with 'Data.Vector.Unboxed.Unbox' and
+-- 'Data.Vector.Unboxed.Storable' instances based on a single
+-- contiguous array storage scheme, suitable for use with
+-- "Data.Vector.Unboxed" and "Data.Vector.Storable".
 --
 -- @
--- interface: [d1 x   y   z  ; d2 x   y   z  ...], length = N = M / 3
+-- interface: [v1 x   y   z  ; v2 x   y   z  ...], length = N = M / 3
 --                |   |   |       |   |   |
--- storage:   [  d1x d2y d2z ;   d2x d2y d2z ...], length = M
+-- storage:   [  v1x v2y v2z ;   v2x v2y v2z ...], length = M
 -- @
-data SVec3 = SVec3 !CDouble !CDouble !CDouble
-             deriving (Eq, Show)
+--
+-- This implementation has the best performance.
+data CVec3 = CVec3 !Double !Double !Double
+              deriving (Eq, Show)
 
 
-instance Storable SVec3 where
+instance Vec3 CVec3 where
+    newtype Matrix CVec3 = UMatrix (CVec3, CVec3, CVec3)
+
+    fromXYZ (x, y, z) = CVec3 x y z
+    {-# INLINE fromXYZ #-}
+
+    toXYZ (CVec3 x y z) = (x, y, z)
+    {-# INLINE toXYZ #-}
+
+    fromRows (r1, r2, r3) = UMatrix (r1, r2, r3)
+    {-# INLINE fromRows #-}
+
+    toRows (UMatrix (r1, r2, r3)) = (r1, r2, r3)
+    {-# INLINE toRows #-}
+
+
+newtype instance VU.MVector s CVec3 = MV_CVec3 (VU.MVector s Double)
+newtype instance VU.Vector    CVec3 = V_CVec3  (VU.Vector    Double)
+
+
+instance VGM.MVector VU.MVector CVec3 where
+    basicInitialize (MV_CVec3 v) =
+        VGM.basicInitialize v
+    {-# INLINE basicInitialize #-}
+
+    basicLength (MV_CVec3 v) =
+        VGM.basicLength v `quot` 3
+    {-# INLINE basicLength #-}
+
+    basicUnsafeSlice s l (MV_CVec3 v) =
+        MV_CVec3 $ VGM.basicUnsafeSlice (s * 3) (l * 3) v
+    {-# INLINE basicUnsafeSlice #-}
+
+    basicOverlaps (MV_CVec3 v1) (MV_CVec3 v2) =
+        VGM.basicOverlaps v1 v2
+    {-# INLINE basicOverlaps #-}
+
+    basicUnsafeNew n =
+        MV_CVec3 `liftM` VGM.basicUnsafeNew (n * 3)
+    {-# INLINE basicUnsafeNew #-}
+
+    basicUnsafeRead (MV_CVec3 v) i = do
+        x <- VGM.basicUnsafeRead v  j
+        y <- VGM.basicUnsafeRead v (j + 1)
+        z <- VGM.basicUnsafeRead v (j + 2)
+        return $ CVec3 x y z
+        where
+          j = i * 3
+    {-# INLINE basicUnsafeRead #-}
+
+    basicUnsafeWrite (MV_CVec3 v) i (CVec3 x y z) =
+        VGM.basicUnsafeWrite v  j      x >>
+        VGM.basicUnsafeWrite v (j + 1) y >>
+        VGM.basicUnsafeWrite v (j + 2) z
+        where
+          j = i * 3
+    {-# INLINE basicUnsafeWrite #-}
+
+
+instance VG.Vector VU.Vector CVec3 where
+    basicUnsafeFreeze (MV_CVec3 v) =
+        V_CVec3 `liftM` VG.basicUnsafeFreeze v
+    {-# INLINE basicUnsafeFreeze #-}
+
+    basicUnsafeThaw (V_CVec3 v) =
+        MV_CVec3 `liftM` VG.basicUnsafeThaw v
+    {-# INLINE basicUnsafeThaw #-}
+
+    basicLength (V_CVec3 v) = VG.basicLength v `quot` 3
+    {-# INLINE basicLength #-}
+
+    basicUnsafeSlice s l (V_CVec3 v) =
+        V_CVec3 $ VG.basicUnsafeSlice (s * 3) (l * 3) v
+    {-# INLINE basicUnsafeSlice #-}
+
+    basicUnsafeIndexM (V_CVec3 v) i = do
+        x <- VG.basicUnsafeIndexM v  j
+        y <- VG.basicUnsafeIndexM v (j + 1)
+        z <- VG.basicUnsafeIndexM v (j + 2)
+        return $ CVec3 x y z
+        where
+          j = i * 3
+    {-# INLINE basicUnsafeIndexM #-}
+
+    basicUnsafeCopy (MV_CVec3 mv) (V_CVec3 v)
+        = VG.basicUnsafeCopy mv v
+    {-# INLINE basicUnsafeCopy #-}
+
+
+instance Unbox CVec3
+
+
+instance Storable CVec3 where
   sizeOf _    = sizeOf (undefined :: CDouble) * 3
   alignment _ = alignment (undefined :: CDouble)
 
@@ -49,12 +151,12 @@
       x <- peekElemOff q 0
       y <- peekElemOff q 1
       z <- peekElemOff q 2
-      return $ SVec3 x y z
+      return $ CVec3 x y z
     where
       q = castPtr p
   {-# INLINE peek #-}
 
-  poke p (SVec3 x y z) = do
+  poke p (CVec3 x y z) = do
       pokeElemOff q 0 x
       pokeElemOff q 1 y
       pokeElemOff q 2 z
@@ -62,30 +164,12 @@
       q = castPtr p
   {-# INLINE poke #-}
 
-
-instance Vec3 SVec3 where
-    newtype Matrix SVec3 = SMatrix (SVec3, SVec3, SVec3)
-                           deriving (Eq, Show)
-
-    fromXYZ (x, y, z) = SVec3 (CDouble x) (CDouble y) (CDouble z)
-    {-# INLINE fromXYZ #-}
-
-    toXYZ (SVec3 (CDouble x) (CDouble y) (CDouble z)) = (x, y, z)
-    {-# INLINE toXYZ #-}
-
-    fromRows (r1, r2, r3) = SMatrix (r1, r2, r3)
-    {-# INLINE fromRows #-}
-
-    toRows (SMatrix (r1, r2, r3)) = (r1, r2, r3)
-    {-# INLINE toRows #-}
-
-
-instance Arbitrary SVec3 where
+instance Arbitrary CVec3 where
   arbitrary = do
     x <- arbitrary
     y <- arbitrary
     z <- arbitrary
     return $ fromXYZ (x, y, z)
 
-  shrink (SVec3 (CDouble x) (CDouble y) (CDouble z)) =
-    map fromXYZ $ shrink (x, y, z)
+  shrink (CVec3 x y z) =
+    Prelude.map fromXYZ $ shrink (x, y, z)
diff --git a/src/Data/Vec3/Tupled.hs b/src/Data/Vec3/Tupled.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Vec3/Tupled.hs
@@ -0,0 +1,64 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeFamilies #-}
+
+module Data.Vec3.Tupled
+    ( TVec3(..)
+    )
+
+where
+
+import Prelude
+
+import Data.Vector.Unboxed.Deriving
+
+import Data.Vec3.Class
+
+
+-- | 'Vec3' implementation with 'Data.Vector.Unboxed.Unbox' instance
+-- based on default Unbox instance for tuples of arrays, which wraps a
+-- vector of tuples as a tuple of vectors.
+--
+-- @
+-- interface:  [v1 (x, y, z); v2 (x, y, z) ...], length = N
+--                  |  |  |       |  |  |
+-- storage(x): [v1x-+  |  | ; v2x-+  |  |  ...], length = N
+-- storage(y): [v1y----+  | ; v2y----+  |  ...], length = N
+-- storage(z): [v1z-------+ ; v2z-------+  ...], length = N
+-- @
+--
+-- You almost definitely want to use 'CVec3' instead as it has better
+-- performance.
+newtype TVec3 = TVec3 (Double, Double, Double)
+               deriving (Eq, Show)
+
+
+derivingUnbox "TVec3"
+  [t|TVec3 -> (Double, Double, Double)|]
+  [|\(TVec3 v) -> v|]
+  [|TVec3|]
+
+
+instance Vec3 TVec3 where
+    newtype Matrix TVec3 = TMatrix (TVec3, TVec3, TVec3)
+                           deriving (Eq, Show)
+
+
+    fromXYZ = TVec3
+    {-# INLINE fromXYZ #-}
+
+    toXYZ (TVec3 v) = v
+    {-# INLINE toXYZ #-}
+
+    fromRows (r1, r2, r3) = TMatrix (r1, r2, r3)
+    {-# INLINE fromRows #-}
+
+    toRows (TMatrix (r1, r2, r3)) = (r1, r2, r3)
+    {-# INLINE toRows #-}
+
+
+derivingUnbox "TMatrix"
+  [t|Matrix TVec3 -> (TVec3, TVec3, TVec3)|]
+  [|\(TMatrix v) -> v|]
+  [|TMatrix|]
diff --git a/src/Data/Vec3/Unboxed.hs b/src/Data/Vec3/Unboxed.hs
deleted file mode 100644
--- a/src/Data/Vec3/Unboxed.hs
+++ /dev/null
@@ -1,64 +0,0 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE TypeFamilies #-}
-
-module Data.Vec3.Unboxed
-    ( UVec3(..)
-    )
-
-where
-
-import Prelude hiding (reverse)
-
-import Data.Vector.Unboxed.Deriving
-
-import Data.Vec3.Class
-
-
--- | 'Vec3' implementation with 'Data.Vector.Unboxed.Unbox' instance
--- based on tuples, suitable for use with "Data.Vector.Unboxed".
---
--- This represents 3-vector as a triple of doubles, using the default
--- Unbox instance for tuples as provided by "Data.Vector.Unboxed",
--- which wraps a vector of tuples as a tuple of vectors.
---
--- @
--- interface:  [d1 (x, y, z); d2 (x, y, z) ...], length = N
---                  |  |  |       |  |  |
--- storage(x): [d1x-+  |  | ; d2x-+  |  |  ...], length = N
--- storage(y): [d1y----+  | ; d2y----+  |  ...], length = N
--- storage(z): [d1z-------+ ; d2z-------+  ...], length = N
--- @
-newtype UVec3 = UVec3 (Double, Double, Double)
-                deriving (Eq, Show)
-
-
-derivingUnbox "UVec3"
-  [t|UVec3 -> (Double, Double, Double)|]
-  [|\(UVec3 v) -> v|]
-  [|UVec3|]
-
-
-instance Vec3 UVec3 where
-    newtype Matrix UVec3 = UMatrix (UVec3, UVec3, UVec3)
-                           deriving (Eq, Show)
-
-
-    fromXYZ = UVec3
-    {-# INLINE fromXYZ #-}
-
-    toXYZ (UVec3 v) = v
-    {-# INLINE toXYZ #-}
-
-    fromRows (r1, r2, r3) = UMatrix (r1, r2, r3)
-    {-# INLINE fromRows #-}
-
-    toRows (UMatrix (r1, r2, r3)) = (r1, r2, r3)
-    {-# INLINE toRows #-}
-
-
-derivingUnbox "UMatrix"
-  [t|Matrix UVec3 -> (UVec3, UVec3, UVec3)|]
-  [|\(UMatrix v) -> v|]
-  [|UMatrix|]
diff --git a/src/Data/Vec3/Unboxed/Contiguous.hs b/src/Data/Vec3/Unboxed/Contiguous.hs
deleted file mode 100644
--- a/src/Data/Vec3/Unboxed/Contiguous.hs
+++ /dev/null
@@ -1,133 +0,0 @@
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE TypeFamilies #-}
-
-{-|
-
-'Vec3' implementation with 'Data.Vector.Unboxed.Unbox' instance based
-on single array storage scheme, suitable for use with
-"Data.Vector.Unboxed".
-
--}
-
-module Data.Vec3.Unboxed.Contiguous
-    ( UVec3(..)
-    )
-
-
-where
-
-import Prelude hiding (reverse)
-
-import Control.Monad
-
-import Data.Vector.Unboxed as VU
-import Data.Vector.Generic as VG
-import Data.Vector.Generic.Mutable as VGM
-
-import Data.Vec3.Class
-
-
--- | 'Vec3' implementation with 'Data.Vector.Unboxed.Unbox' instance
--- based on a single contiguous array storage scheme, suitable for use
--- with "Data.Vector.Unboxed".
---
--- 'Unbox' instance provides the required index transformations.
---
--- @
--- interface: [d1 x   y   z  ; d2 x   y   z  ...], length = N = M / 3
---                |   |   |       |   |   |
--- storage:   [  d1x d2y d2z ;   d2x d2y d2z ...], length = M
--- @
-data UVec3 = UVec3 !Double !Double !Double
-              deriving (Eq, Show)
-
-
-instance Vec3 UVec3 where
-    newtype Matrix UVec3 = UMatrix (UVec3, UVec3, UVec3)
-
-    fromXYZ (x, y, z) = UVec3 x y z
-    {-# INLINE fromXYZ #-}
-
-    toXYZ (UVec3 x y z) = (x, y, z)
-    {-# INLINE toXYZ #-}
-
-    fromRows (r1, r2, r3) = UMatrix (r1, r2, r3)
-    {-# INLINE fromRows #-}
-
-    toRows (UMatrix (r1, r2, r3)) = (r1, r2, r3)
-    {-# INLINE toRows #-}
-
-
-newtype instance VU.MVector s UVec3 = MV_UVec3 (VU.MVector s Double)
-newtype instance VU.Vector    UVec3 = V_UVec3  (VU.Vector    Double)
-
-
-instance VGM.MVector VU.MVector UVec3 where
-    basicInitialize (MV_UVec3 v) =
-        VGM.basicInitialize v
-    {-# INLINE basicInitialize #-}
-
-    basicLength (MV_UVec3 v) =
-        VGM.basicLength v `quot` 3
-    {-# INLINE basicLength #-}
-
-    basicUnsafeSlice s l (MV_UVec3 v) =
-        MV_UVec3 $ VGM.basicUnsafeSlice (s * 3) (l * 3) v
-    {-# INLINE basicUnsafeSlice #-}
-
-    basicOverlaps (MV_UVec3 v1) (MV_UVec3 v2) =
-        VGM.basicOverlaps v1 v2
-    {-# INLINE basicOverlaps #-}
-
-    basicUnsafeNew n =
-        MV_UVec3 `liftM` VGM.basicUnsafeNew (n * 3)
-    {-# INLINE basicUnsafeNew #-}
-
-    basicUnsafeRead (MV_UVec3 v) i = do
-        x <- VGM.basicUnsafeRead v  j
-        y <- VGM.basicUnsafeRead v (j + 1)
-        z <- VGM.basicUnsafeRead v (j + 2)
-        return $ UVec3 x y z
-        where
-          j = i * 3
-    {-# INLINE basicUnsafeRead #-}
-
-    basicUnsafeWrite (MV_UVec3 v) i (UVec3 x y z) =
-        VGM.basicUnsafeWrite v  j      x >>
-        VGM.basicUnsafeWrite v (j + 1) y >>
-        VGM.basicUnsafeWrite v (j + 2) z
-        where
-          j = i * 3
-    {-# INLINE basicUnsafeWrite #-}
-
-
-instance VG.Vector VU.Vector UVec3 where
-    basicUnsafeFreeze (MV_UVec3 v) =
-        V_UVec3 `liftM` VG.basicUnsafeFreeze v
-    {-# INLINE basicUnsafeFreeze #-}
-
-    basicUnsafeThaw (V_UVec3 v) =
-        MV_UVec3 `liftM` VG.basicUnsafeThaw v
-    {-# INLINE basicUnsafeThaw #-}
-
-    basicLength (V_UVec3 v) = VG.basicLength v `quot` 3
-    {-# INLINE basicLength #-}
-
-    basicUnsafeSlice s l (V_UVec3 v) =
-        V_UVec3 $ VG.basicUnsafeSlice (s * 3) (l * 3) v
-    {-# INLINE basicUnsafeSlice #-}
-
-    basicUnsafeIndexM (V_UVec3 v) i = do
-        x <- VG.basicUnsafeIndexM v  j
-        y <- VG.basicUnsafeIndexM v (j + 1)
-        z <- VG.basicUnsafeIndexM v (j + 2)
-        return $ UVec3 x y z
-        where
-          j = i * 3
-    {-# INLINE basicUnsafeIndexM #-}
-
-    basicUnsafeCopy (MV_UVec3 mv) (V_UVec3 v)
-        = VG.basicUnsafeCopy mv v
-    {-# INLINE basicUnsafeCopy #-}
-
-instance Unbox UVec3
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -7,13 +7,13 @@
 
 
 infix 4 <~=>
-(<~=>) :: SVec3 -> SVec3 -> Bool
+(<~=>) :: CVec3 -> CVec3 -> Bool
 (<~=>) a b = ax ~= bx &&
              ay ~= by &&
              az ~= bz
   where
-    (ax, ay, az) = toXYZ (a :: SVec3)
-    (bx, by, bz) = toXYZ (b :: SVec3)
+    (ax, ay, az) = toXYZ (a :: CVec3)
+    (bx, by, bz) = toXYZ (b :: CVec3)
 
 
 infix 4 ~=
@@ -30,37 +30,37 @@
 tests =
   [ testProperty
     "Commutativity of addition: a + b = b + a"
-    (\(a :: SVec3) b -> a <+> b <~=> b <+> a)
+    (\(a :: CVec3) b -> a <+> b <~=> b <+> a)
   , testProperty
     "Associativity of addition: (a + b) + c = a + (b + c)"
-    (\(a :: SVec3) b c -> (a <+> b) <+> c <~=> a <+> (b <+> c))
+    (\(a :: CVec3) b c -> (a <+> b) <+> c <~=> a <+> (b <+> c))
   , testProperty
     "Identity element of addition (zero): v + 0 = v"
-    (\(v :: SVec3) -> (v <+> origin <~=> v))
+    (\(v :: CVec3) -> (v <+> origin <~=> v))
   , testProperty
     "Inverse elements of addition: v + (-v) = 0"
-    (\(v :: SVec3) -> (v <+> invert v <~=> origin))
+    (\(v :: CVec3) -> (v <+> invert v <~=> origin))
   , testProperty
     "Compatibility of scalar and field multiplication"
-    (\(v :: SVec3) p q -> (v .^ p .^ q <~=> v .^ (p * q)))
+    (\(v :: CVec3) p q -> (v .^ p .^ q <~=> v .^ (p * q)))
   , testProperty
     "Identity of scalar multiplication"
-    (\(v :: SVec3) -> (v .^ 1 <~=> v))
+    (\(v :: CVec3) -> (v .^ 1 <~=> v))
   , testProperty
     "Distributivity wrt vector addition"
-    (\(a :: SVec3) b p -> ((a <+> b) .^ p) <~=> (a .^ p) <+> (b .^ p))
+    (\(a :: CVec3) b p -> ((a <+> b) .^ p) <~=> (a .^ p) <+> (b .^ p))
   , testProperty
     "Distributivity wrt scalar addition"
-    (\(a :: SVec3) p q -> (a .^ (p + q) <~=> (a .^ p) <+> (a .^ q)))
+    (\(a :: CVec3) p q -> (a .^ (p + q) <~=> (a .^ p) <+> (a .^ q)))
   , testProperty
     "Subtraction definition"
-    (\(a :: SVec3) b -> (a <+> invert b <~=> a <-> b))
+    (\(a :: CVec3) b -> (a <+> invert b <~=> a <-> b))
   , testProperty
     "Normalization"
-    (\(v :: SVec3) -> (v <~=> origin || norm (normalize v) ~= 1))
+    (\(v :: CVec3) -> (v <~=> origin || norm (normalize v) ~= 1))
   , testProperty
     "Triangle inequality"
-    (\(a :: SVec3) b c -> (distance a b + distance b c >= distance a c))
+    (\(a :: CVec3) b c -> (distance a b + distance b c >= distance a c))
   ]
 
 
