From 2d4beed9cd56d29000fa811ded1288461adb9ac1 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 4 Feb 2013 15:14:38 -0500 Subject: [PATCH] Encode the vector type in Vn. Add FixedVector.length. Add FixedVector.map. Include a special 4D type. --- src/FixedVector.hs | 94 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/src/FixedVector.hs b/src/FixedVector.hs index 8848b9b..402b02e 100644 --- a/src/FixedVector.hs +++ b/src/FixedVector.hs @@ -14,10 +14,13 @@ import Normed -- | The Vn newtype simply wraps (Vector v a) so that we avoid -- undecidable instances. -newtype Vn a = Vn a +newtype Vn v a = Vn (v a) +-- | Declare the dimension of the wrapper to be the dimension of what +-- it contains. +type instance V.Dim (Vn v) = V.Dim v -instance (Show a, V.Vector v a) => Show (Vn (v a)) where +instance (Show a, V.Vector v a) => Show (Vn v a) where -- | Display vectors as ordinary tuples. This is poor practice, but -- these results are primarily displayed interactively and -- convenience trumps correctness (said the guy who insists his @@ -50,14 +53,14 @@ instance (Show a, V.Vector v a) => Show (Vn (v a)) where -- >>> v1 == v3 -- False -- -instance (Eq a, V.Vector v a, V.Vector v Bool) => Eq (Vn (v a)) where +instance (Eq a, V.Vector v a, V.Vector v Bool) => Eq (Vn v a) where (Vn v1) == (Vn v2) = V.foldl (&&) True (V.zipWith (==) v1 v2) -- | The use of 'Num' here is of course incorrect (otherwise, we -- wouldn't have to throw errors). But it's really nice to be able -- to use normal addition/subtraction. -instance (Num a, V.Vector v a) => Num (Vn (v a)) where +instance (Num a, V.Vector v a) => Num (Vn v a) where -- | Componentwise addition. -- -- Examples: @@ -86,7 +89,7 @@ instance (Num a, V.Vector v a) => Num (Vn (v a)) where -- -- Examples: -- - -- >>> let v1 = fromInteger 17 :: Vn (Vec3 Int) + -- >>> let v1 = fromInteger 17 :: Vn Vec3 Int -- (17,17,17) -- fromInteger x = Vn $ V.replicate (fromInteger x) @@ -94,10 +97,14 @@ instance (Num a, V.Vector v a) => Num (Vn (v a)) where abs = error "absolute value of vectors is undefined" signum = error "signum of vectors is undefined" -instance Functor Vn where - fmap f (Vn v1) = Vn (f v1) -instance (RealFloat a, Ord a, V.Vector v a) => Normed (Vn (v a)) where +-- | This is probably useless, since the vectors we usually contain +-- aren't functor instances. +instance (Functor v) => Functor (Vn v) where + fmap f (Vn v1) = Vn (f `fmap` v1) + + +instance (RealFloat a, Ord a, V.Vector v a) => Normed (Vn v a) where -- | The infinity norm. We don't use V.maximum here because it -- relies on a type constraint that the vector be non-empty and I -- don't know how to pattern match it away. @@ -135,7 +142,7 @@ instance (RealFloat a, Ord a, V.Vector v a) => Normed (Vn (v a)) where -- >>> dot v1 v2 -- 32 -- -dot :: (Num a, V.Vector v a) => Vn (v a) -> Vn (v a) -> a +dot :: (Num a, V.Vector v a) => Vn v a -> Vn v a -> a dot (Vn v1) (Vn v2) = V.sum $ V.zipWith (*) v1 v2 @@ -148,13 +155,26 @@ dot (Vn v1) (Vn v2) = V.sum $ V.zipWith (*) v1 v2 -- >>> angle v1 v2 == pi/2.0 -- True -- -angle :: (RealFloat a, V.Vector v a) => Vn (v a) -> Vn (v a) -> a +angle :: (RealFloat a, V.Vector v a) => Vn v a -> Vn v a -> a angle v1 v2 = acos theta where theta = (v1 `dot` v2) / norms norms = (norm v1) * (norm v2) + +-- | The length of a vector. +-- +-- Examples: +-- +-- >>> let v1 = make2d (1,2) +-- >>> length v1 +-- 2 +-- +length :: (V.Vector v a) => Vn v a -> Int +length (Vn v1) = V.length v1 + + -- | Unsafe indexing. -- -- Examples: @@ -165,7 +185,7 @@ angle v1 v2 = -- >>> v1 ! 3 -- *** Exception: Data.Vector.Fixed.!: index out of range -- -(!) :: (V.Vector v a) => Vn (v a) -> Int -> a +(!) :: (V.Vector v a) => Vn v a -> Int -> a (!) (Vn v1) idx = v1 V.! idx @@ -179,7 +199,7 @@ angle v1 v2 = -- >>> v1 !? 3 -- Nothing -- -(!?) :: (V.Vector v a) => Vn (v a) -> Int -> Maybe a +(!?) :: (V.Vector v a) => Vn v a -> Int -> Maybe a (!?) v1@(Vn v2) idx | idx < 0 || idx >= V.length v2 = Nothing | otherwise = Just $ v1 ! idx @@ -193,7 +213,7 @@ angle v1 v2 = -- >>> toList v1 -- [1,2] -- -toList :: (V.Vector v a) => Vn (v a) -> [a] +toList :: (V.Vector v a) => Vn v a -> [a] toList (Vn v1) = V.toList v1 @@ -201,16 +221,29 @@ toList (Vn v1) = V.toList v1 -- -- Examples: -- --- >>> fromList [1,2] :: Vn (Vec2D Int) +-- >>> fromList [1,2] :: Vn Vec2D Int -- (1,2) -- -fromList :: (V.Vector v a) => [a] -> Vn (v a) +fromList :: (V.Vector v a) => [a] -> Vn v a fromList xs = Vn $ V.fromList xs --- * Two- and three-dimensional wrappers. +-- | Map a function over a vector. +-- +-- Examples: +-- +-- >>> let v1 = make2d (1,2) +-- >>> map (*2) v1 +-- (2,4) +-- +map :: (V.Vector v a, V.Vector v b) => (a -> b) -> Vn v a -> Vn v b +map f (Vn vs) = Vn $ V.map f vs + + + +-- * Low-dimension vector wrappers. -- --- These two wrappers are instances of 'Vector', so they inherit all --- of the userful instances defined above. But, they use fixed +-- These wrappers are instances of 'Vector', so they inherit all of +-- the userful instances defined above. But, they use fixed -- constructors, so you can pattern match out the individual -- components. @@ -226,6 +259,12 @@ instance V.Vector Vec3D a where inspect (Vec3D x y z) (V.Fun f) = f x y z construct = V.Fun Vec3D +data Vec4D a = Vec4D a a a a +type instance V.Dim Vec4D = V.N4 +instance V.Vector Vec4D a where + inspect (Vec4D w x y z) (V.Fun f) = f w x y z + construct = V.Fun Vec4D + -- | Convenience function for creating 2d vectors. -- @@ -238,7 +277,7 @@ instance V.Vector Vec3D a where -- >>> (x,y) -- (1,2) -- -make2d :: forall a. (a,a) -> Vn (Vec2D a) +make2d :: forall a. (a,a) -> Vn Vec2D a make2d (x,y) = Vn (Vec2D x y) @@ -253,5 +292,20 @@ make2d (x,y) = Vn (Vec2D x y) -- >>> (x,y,z) -- (1,2,3) -- -make3d :: forall a. (a,a,a) -> Vn (Vec3D a) +make3d :: forall a. (a,a,a) -> Vn Vec3D a make3d (x,y,z) = Vn (Vec3D x y z) + + +-- | Convenience function for creating 4d vectors. +-- +-- Examples: +-- +-- >>> let v1 = make4d (1,2,3,4) +-- >>> v1 +-- (1,2,3,4) +-- >>> let Vn (Vec4D w x y z) = v1 +-- >>> (w,x,y,z) +-- (1,2,3,4) +-- +make4d :: forall a. (a,a,a,a) -> Vn Vec4D a +make4d (w,x,y,z) = Vn (Vec4D w x y z) -- 2.44.2