Hi,
I'm seeing the following bug revived in 6.8.2 and 6.8.3:
http://hackage.haskell.org/trac/ghc/ticket/672
I use a default definition for class method, one that calls methods of
dependent (super?) classes. Of course I'm embarrassed it took me so long to
realize I didn't _need_ the class in the first place, I could just write a
plain polymorphic function that calls those methods. Regardless, looks like
a bug to me.
Two files are attached, Test.hs and Vec.hs. Search for "BUG IS HERE" in
Test.hs. There is a class and an instance declaration. Compile as-is to see
the correct result. Comment out the method definition in the instance
declaration to see the bug.
If someone confirms, I'll open a ticket.
Scott
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}
-- Vec : a library for fixed-length lists.
module Vec where
import Prelude hiding (map,zipWith,foldl,foldr,reverse,take,drop,head,tail,sum,length)
import qualified Prelude as P
import Foreign.Storable
import Foreign.Ptr
-- The vector type. (:.) for vectors is like (:) for lists, and () takes the
-- place of [].
data a :. b = (:.) !a !b
deriving (Eq,Ord,Read)
infixr :.
instance (Show a, Show v) => Show (a:.v) where
show (a:.v) = show a ++ ":. (" ++ show v ++ ")"
-- Some vectors. I heard somewhere that 7 was the magic number for tuples. So
-- be it for vectors as well.
type Vec2 a = a :. a :. ()
type Vec3 a = a :. (Vec2 a)
type Vec4 a = a :. (Vec3 a)
type Vec5 a = a :. (Vec4 a)
type Vec6 a = a :. (Vec5 a)
type Vec7 a = a :. (Vec6 a)
-- Some square matrices
type Mat22 a = Vec2 (Vec2 a)
type Mat23 a = Vec2 (Vec3 a)
type Mat33 a = Vec3 (Vec3 a)
type Mat34 a = Vec3 (Vec4 a)
type Mat44 a = Vec4 (Vec4 a)
-- Vec is the basic vector class, which is used to infer vector types from
-- their length and underlying component type. Some other functions, like
-- converting from lists, also fit in with the recursion here.
class Vec n a v | n a -> v, v -> n a where
mkVec :: n -> a -> v
-- make a uniform vector of a given length
vecFromList :: [a] -> v
-- turn a list into a vector of known length
getd :: Int -> v -> a
-- get a vector element, which one is determined at runtime
setd :: Int -> a -> v -> v
-- set a vector element, which one is determined at runtime
--Make a uniform vector. The length is inferred.
vec = mkVec undefined
instance Vec N1 a ( a :. () ) where
mkVec _ a = a :. ()
vecFromList (a:_) = a :. ()
vecFromList [] = error "vecFromList: list too short"
getd !i (a :. _)
| i == 0 = a
| otherwise = error ("getd: index out of bounds")
setd !i a _
| i == 0 = a :. ()
| otherwise = error ("setd: index out of bounds")
{-# INLINE setd #-}
{-# INLINE getd #-}
{-# INLINE mkVec #-}
{-# INLINE vecFromList #-}
instance Vec (Succ n) a (a':.v) => Vec (Succ (Succ n)) a (a:.a':.v) where
mkVec _ a = a :. (mkVec undefined a)
vecFromList (a:as) = a :. (vecFromList as)
vecFromList [] = error "vecFromList: list too short"
getd !i (a :. v)
| i == 0 = a
| otherwise = getd (i-1) v
setd !i a (x :. v)
| i == 0 = a :. v
| otherwise = x :. (setd (i-1) a v)
{-# INLINE setd #-}
{-# INLINE getd #-}
{-# INLINE mkVec #-}
{-# INLINE vecFromList #-}
--Type level naturals.
data N0
data Succ a
type N1 = Succ N0
type N2 = Succ N1
type N3 = Succ N2
type N4 = Succ N3
type N5 = Succ N4
type N6 = Succ N5
type N7 = Succ N6
type N8 = Succ N7
type N9 = Succ N8
type N10 = Succ N9
type N11 = Succ N10
type N12 = Succ N11
type N13 = Succ N12
type N14 = Succ N13
type N15 = Succ N14
type N16 = Succ N15
type N17 = Succ N16
type N18 = Succ N17
type N19 = Succ N18
n0 :: N0 ; n0 = undefined
n1 :: N1 ; n1 = undefined
n2 :: N2 ; n2 = undefined
n3 :: N3 ; n3 = undefined
n4 :: N4 ; n4 = undefined
n5 :: N5 ; n5 = undefined
n6 :: N6 ; n6 = undefined
n7 :: N7 ; n7 = undefined
n8 :: N8 ; n8 = undefined
n9 :: N9 ; n9 = undefined
n10 :: N10 ; n10 = undefined
n11 :: N11 ; n11 = undefined
n12 :: N12 ; n12 = undefined
n13 :: N13 ; n13 = undefined
n14 :: N14 ; n14 = undefined
n15 :: N15 ; n15 = undefined
n16 :: N16 ; n16 = undefined
n17 :: N17 ; n17 = undefined
n18 :: N18 ; n18 = undefined
n19 :: N19 ; n19 = undefined
class Nat n where nat :: n -> Int
instance Nat N0 where nat _ = 0
instance Nat a => Nat (Succ a) where nat _ = 1+(nat (undefined::a))
class Pred x y | x -> y, y -> x
instance Pred (Succ N0) N0
instance Pred (Succ n) p => Pred (Succ (Succ n)) (Succ p)
--Access: getting/setting vector elements, which one determined at compile
--time. Use the Nat types to access vector components. For instance, (get n0)
--gets the x component, (set n2 44) sets the z component to 44.
class Access n a v | v -> a where
get :: n -> v -> a
set :: n -> a -> v -> v
instance Access N0 a (a :. v) where
get _ (a :. _) = a
set _ a (_ :. v) = a :. v
{-# INLINE set #-}
{-# INLINE get #-}
instance Access n a v => Access (Succ n) a (a :. v) where
get _ (_ :. v) = get (undefined::n) v
set _ a' (a :. v) = a :. (set (undefined::n) a' v)
{-# INLINE set #-}
{-# INLINE get #-}
class Head v a | v -> a where head :: v -> a
instance Head (a :. as) a where
head (a :. _) = a
{-# INLINE head #-}
class Tail v v_ | v -> v_ where tail :: v -> v_
instance Tail (a :. as) as where
tail (_ :. as) = as
{-# INLINE tail #-}
-- Map, ZipWith and Fold. The function is applied strictly.
class Map a b u v | u -> a, v -> b, u b -> v a, v a -> u b where
map :: (a -> b) -> u -> v
instance Map a b (a :. ()) (b :. ()) where
map !f !(x :. ()) = (f $! x) :. ()
{-# INLINE map #-}
instance Map a b (a':.u) (b':.v) => Map a b (a:.a':.u) (b:.b':.v) where
map !f !(x:.v) = (f $! x):.(map f v)
{-# INLINE map #-}
--strictly2 : strict binary function application
strictly2 f a b = (f $! a) $! b
{-# INLINE strictly2 #-}
class ZipWith a b c u v w | u->a, v->b, w->c, u c -> w, w a -> u where
zipWith :: (a -> b -> c) -> u -> v -> w
instance ZipWith a b c (a:.()) (b:.()) (c:.()) where
zipWith f (x:.()) (y:.()) = strictly2 f x y :.()
{-# INLINE zipWith #-}
instance
ZipWith a b c (a':.u) (b':.v) (c':.w)
=> ZipWith a b c (a:.a':.u) (b:.b':.v) (c:.c':.w)
where
zipWith f (x:.u) (y:.v) = (strictly2 f x y):.(zipWith f u v)
{-# INLINE zipWith #-}
-- The fold function is like fold1. Whether it's left or right doesn't matter.
class Fold a v | v -> a where
fold :: (a -> a -> a) -> v -> a
foldl :: (b -> a -> b) -> b -> v -> b
foldr :: (a -> b -> b) -> b -> v -> b
instance Fold a (a:.()) where
fold f (a:._) = a
foldl f z (a:._) = strictly2 f z a
foldr f z (a:._) = strictly2 f a z
{-# INLINE fold #-}
{-# INLINE foldl #-}
{-# INLINE foldr #-}
instance Fold a (a:.u) => Fold a (a:.a:.u) where
fold f (a:.v) = strictly2 f a (fold f v)
foldl f z (a:.v) = strictly2 f (foldl f z v) a
foldr f z (a:.v) = strictly2 f a (foldr f z v)
{-# INLINE fold #-}
{-# INLINE foldl #-}
{-# INLINE foldr #-}
sum x = fold (+) x
product x = fold (*) x
maximum x = fold max x
minimum x = fold min x
{-# INLINE sum #-}
{-# INLINE product #-}
{-# INLINE maximum #-}
{-# INLINE minimum #-}
vecToList = foldr (:) []
{-# INLINE vecToList #-}
-- convert matrices to/from lists of lists.
matToLists = (P.map vecToList) . vecToList
matToList = concat . matToLists
matFromLists = vecFromList . (P.map vecFromList)
matFromList :: forall m n row mat elem. (Vec m row mat, Vec n elem row, Nat n) => [elem] -> mat
matFromList = matFromLists . groupsOf (nat(undefined::n))
where groupsOf n xs = let (a,b) = splitAt n xs in a:(groupsOf n b)
{-# INLINE matToLists #-}
{-# INLINE matToList #-}
{-# INLINE matFromLists #-}
{-# INLINE matFromList #-}
class Reverse v where
reverse :: v -> v
instance
(Reverse' (a:.()) v (a:.v))
=> Reverse (a:.v)
where
reverse (a:.v) = reverse' (a:.()) v
{-# INLINE reverse #-}
-- Reverse helper function : builds the reversed list as its first argument
class Reverse' p v v' | p v -> v' where
reverse' :: p -> v -> v'
instance Reverse' p (a:.()) (a:.p) where
reverse' p (a:.()) = a:.p
{-# INLINE reverse' #-}
instance Reverse' (a:.p) v v' => Reverse' p (a:.v) v' where
reverse' p (a:.v) = reverse' (a:.p) v
{-# INLINE reverse' #-}
class Append v1 v2 v3 | v1 v2 -> v3, v1 v3 -> v2 where
append :: v1 -> v2 -> v3
instance Append () v v where
append _ = id
{-# INLINE append #-}
instance Append (a:.()) v (a:.v) where
append (a:.()) v = a:.v
{-# INLINE append #-}
instance (Append (a':.v1) v2 v3) => Append (a:.a':.v1) v2 (a:.v3) where
append (a:.u) v = a:.(append u v)
{-# INLINE append #-}
-- Take and Drop : the amount to take or drop is known at compile time, as it
-- must be to infer the result type.
class Take n a v v' | n v -> v', n v' -> v, v -> a, v' -> a where
take :: n -> v -> v'
instance Take N0 a v () where
take _ _ = ()
{-# INLINE take #-}
instance Take n a v v' => Take (Succ n) a (a:.v) (a:.v') where
take _ (a:.v) = a:.(take (undefined::n) v)
{-# INLINE take #-}
class Drop n a v v' | n v -> v', n v' -> v, v -> a, v' -> a where
drop :: n -> v -> v'
instance Drop N0 a v v where
drop _ = id
{-# INLINE drop #-}
instance (Tail v' v'', Drop n a v v') => Drop (Succ n) a v v'' where
drop _ = tail . drop (undefined::n)
{-# INLINE drop #-}
--Num and Fractional instances. Everything is done component-wise. This is not
--at all consistent with mathematical convention. However I find it
--convenient. For instance, fromIntegral and realToFrac create uniform
--vectors from their arguments, so multiplying a vector by a scalar is just
--2 * v, and likewise for multiplying a matrix by a scalar. The literal 0 gives
--you either the null vector or a matrix of zeros, depending on the type.
instance
(Eq (a:.u)
,Show (a:.u)
,Num a
,Map a a (a:.u) (a:.u)
,ZipWith a a a (a:.u) (a:.u) (a:.u)
,Vec (Succ l) a (a:.u)
)
=> Num (a:.u)
where
(+) u v = zipWith (+) u v
(-) u v = zipWith (-) u v
(*) u v = zipWith (*) u v
abs u = map abs u
signum u = map signum u
fromInteger i = vec (fromInteger i)
{-# INLINE (+) #-}
{-# INLINE (-) #-}
{-# INLINE (*) #-}
{-# INLINE abs #-}
{-# INLINE signum #-}
{-# INLINE fromInteger #-}
instance
(Fractional a
,Ord (a:.u)
,ZipWith a a a (a:.u) (a:.u) (a:.u)
,Map a a (a:.u) (a:.u)
,Vec (Succ l) a (a:.u)
,Show (a:.u)
)
=> Fractional (a:.u)
where
(/) u v = zipWith (/) u v
recip u = map recip u
fromRational r = vec (fromRational r)
{-# INLINE (/) #-}
{-# INLINE recip #-}
{-# INLINE fromRational #-}
-- dot / inner / scalar product
dot u v = sum (u*v)
{-# INLINE dot #-}
-- vector norm, squared
normSq v = dot v v
{-# INLINE normSq #-}
-- vector norm
norm v = sqrt (dot v v)
{-# INLINE norm #-}
-- a unit vector in the direction of v
normalize v = map (/(norm v)) v
{-# INLINE normalize #-}
-- Matrix transpose wrapper class: infers type of one argument from the other,
-- because Transpose` can't do it, the fundeps there are not bijective
class Transpose a b | a -> b, b -> a where
transpose :: a -> b
instance Transpose () () where
transpose = id
instance
(Vec n s ra --ra is an n-vector of s'es (row of a)
,Vec m ra a --a is an m-vector of ra's
,Vec m s rb --rb is an m-vector of s'es (row of b)
,Vec n rb b --b is an n-vector of rb's
,Transpose' a b
)
=> Transpose a b
where
transpose = transpose'
{-# INLINE transpose #-}
class Transpose' a b | a->b
where transpose' :: a -> b
instance Transpose' () () where
transpose' = id
{-# INLINE transpose' #-}
instance
(Transpose' vs vs') => Transpose' ( () :. vs ) vs'
where
transpose' (():.vs) = transpose' vs
{-# INLINE transpose' #-}
instance Transpose' ((x:.()):.()) ((x:.()):.()) where
transpose' = id
instance
(Head xss_h xss_hh
,Map xss_h xss_hh (xss_h:.xss_t) xs'
,Tail xss_h xss_ht
,Map xss_h xss_ht (xss_h:.xss_t) xss_
,Transpose' (xs :. xss_) xss'
)
=> Transpose' ((x:.xs):.(xss_h:.xss_t)) ((x:.xs'):.xss')
where
transpose' ((x:.xs):.xss) =
(x :. (map head xss)) :. (transpose' (xs :. (map tail xss)))
{-# inline transpose' #-}
-- row vector * matrix
multvm v m = map (dot v) (transpose m)
{-# INLINE multvm #-}
-- matrix * column vector
multmv m v = map (dot v) m
{-# INLINE multmv #-}
-- matrix * matrix
multmm a b = map (\v -> map (dot v) (transpose b)) a
{-# INLINE multmm #-}
class SetDiagonal v m | m -> v where
setDiagonal :: v -> m -> m
--set the diagonal of an n-by-n matrix to a given n-vector
instance (Vec n a v, Vec n r m, SetDiagonal' N0 v m) => SetDiagonal v m where
setDiagonal v m = setDiagonal' (undefined::N0) v m
{-# INLINE setDiagonal #-}
class SetDiagonal' n v m where
setDiagonal' :: n -> v -> m -> m
instance SetDiagonal' n () m where
setDiagonal' _ _ m = m
{-# INLINE setDiagonal' #-}
instance
(SetDiagonal' (Succ n) v m
,Access n a r
)
=> SetDiagonal' n (a:.v) (r:.m)
where
setDiagonal' _ (a:.v) (r:.m) =
(set (undefined::n) a r) :. (setDiagonal' (undefined::Succ n) v m)
{-# INLINE setDiagonal' #-}
class GetDiagonal m v | m -> v, v -> m where
getDiagonal :: m -> v
--get the diagonal of an n-by-n matrix as a vector
instance (Vec n a v, Vec n v m, GetDiagonal' N0 () m v) => GetDiagonal m v where
getDiagonal m = getDiagonal' (undefined::N0) () m
{-# INLINE getDiagonal #-}
class GetDiagonal' n p m v where
getDiagonal' :: n -> p -> m -> v
instance
(Access n a r
,Append p (a:.()) (a:.p)
) => GetDiagonal' n p (r:.()) (a:.p)
where
getDiagonal' _ p (r:.()) = append p ((get (undefined::n) r) :. ())
{-# INLINE getDiagonal' #-}
instance
(Access n a r
,Append p (a:.()) p'
,GetDiagonal' (Succ n) p' m v
)
=> GetDiagonal' n p (r:.m) v
where
getDiagonal' _ p (r:.m) =
getDiagonal' (undefined::Succ n) (append p ( (get (undefined::n) r):.())) m
{-# INLINE getDiagonal' #-}
--scale : multiply the diagonal of matrix m by the vector s, component-wise. So
--(scale 5 m) multiplies the diagonal by 5, whereas (scale (vec(2,1,1,..)) m)
--only scales the x-dimension.
scale s m = setDiagonal (s * (getDiagonal m)) m
{-# INLINE scale #-}
--diagonal : construct a matrix with the vector v as the diagonal, and 0
--elsewhere.
diagonal :: (Vec n a v, Vec n v m, SetDiagonal v m, Num m) => v -> m
diagonal v = setDiagonal v 0
{-# INLINE diagonal #-}
--identity matrix
identity :: (Vec n a v, Vec n v m, Num v, Num m, SetDiagonal v m) => m
identity = diagonal 1
{-# INLINE identity #-}
-- cross / outter / vector product, for 3-vectors only
cross :: Num a => Vec3 a -> Vec3 a -> Vec3 a
cross (ux:.uy:.uz:.()) (vx:.vy:.vz:.()) =
(uy*vz-uz*vy):.(uz*vx-ux*vz):.(ux*vy-uy*vx):.()
{-# INLINE cross #-}
-- DropConsec: this is a helper function for computing determinants. Given an
-- n-vector v, drop each element from v and collect the remaning (n-1)-vectors
-- into an n-vector (ie an n-by-(n-1) matrix)
class DropConsec v vv | v -> vv where
dropConsec :: v -> vv
instance
(Vec n a v
,Pred n n_
,Vec n_ a v_
,Vec n v_ vv
,DropConsec' () v vv
) => DropConsec v vv
where
dropConsec v = dropConsec' () v :: vv
{-# INLINE dropConsec #-}
class DropConsec' p v vv where
dropConsec' :: p -> v -> vv
instance DropConsec' p (a:.()) (p:.()) where
dropConsec' p (a:.()) = (p:.())
{-# INLINE dropConsec' #-}
instance
(Append p (a:.v) x
,Append p (a:.()) y
,DropConsec' y (a:.v) z
)
=> DropConsec' p (a:.a:.v) (x:.z)
where
dropConsec' !p (a:.v) =
(append p v) :. (dropConsec' (append p (a:.())) v)
{-# INLINE dropConsec' #-}
--Alternating: vector of alternating positive/negative values. This is also a
--helper for computing determinants
class Alternating n a v | v -> n a where
alternating :: n -> a -> v
instance Alternating N1 a (a:.()) where
alternating _ !a = a:.()
{-# INLINE alternating #-}
instance (Num a, Alternating n a (a:.v)) => Alternating (Succ n) a (a:.a:.v) where
alternating _ !a = a:.(alternating (undefined::n) (negate a))
{-# INLINE alternating #-}
-- The Determinant of a square matrix
class Det a m | m -> a where
det :: m -> a
instance Num a => Det a ((a:.a:.()):.(a:.a:.()):.()) where
det ( (a:.b:.()) :. (c:.d:.()) :. () ) = a*d-b*c
{-# INLINE det #-}
instance
(Num a
,Num (a:.a:.a:.v)
,Fold a (a:.a:.a:.v)
,Alternating (Succ (Succ (Succ n))) a (a:.a:.a:.v)
,DropConsec (a:.a:.a:.v) vv
,Map (a:.a:.a:.v) vv ((a:.a:.a:.v):.(a:.a:.a:.v):.m) vmt
,Transpose vmt vm
,Map ((a:.a:.v):.(a:.a:.v):.m_) a vm (a:.a:.a:.v)
,Det a ((a:.a:.v):.(a:.a:.v):.m_)
,Vec (Succ (Succ (Succ n))) a (a:.a:.a:.v)
,Vec (Succ (Succ (Succ n))) (a:.a:.a:.v) ((a:.a:.a:.v):.(a:.a:.a:.v):.(a:.a:.a:.v):.m)
)
=>
Det a ((a:.a:.a:.v):.(a:.a:.a:.v):.(a:.a:.a:.v):.m)
where
det (mh:.mt) =
let m2 = map dropConsec mt :: vmt
in
sum ((alternating undefined 1) * mh *
(map det (transpose m2)))
{-# INLINE det #-}
--ReplConsec : this is a helper for solving a linear system. Given an n-vector
--v and a value r, replace each consecutive element from v with r, and collect
--the resulting n-vectors into an n-vector (ie an n-by-n matrix)
class ReplConsec a v vv | v -> vv where
replConsec :: a -> v -> vv
instance
(Vec n a v
,Vec n v vv
,ReplConsec' a () v vv
) => ReplConsec a v vv
where
replConsec a v = replConsec' a () v :: vv
{-# INLINE replConsec #-}
class ReplConsec' a p v vv where
replConsec' :: a -> p -> v -> vv
instance ReplConsec' a p () () where
replConsec' _ _ () = ()
{-# INLINE replConsec' #-}
instance
(Append p (a:.v) x
,Append p (a:.()) y
,ReplConsec' a y v z
)
=> ReplConsec' a p (a:.v) (x:.z)
where
replConsec' !r !p ((!a):.(!v)) =
(append p (r:.v)) :. (replConsec' r (append p (a :. ())) v)
{-# INLINE replConsec' #-}
-- solution of linear system by Cramer's rule
solve !m !b =
map (\m' -> (det m')/(det m)) (transpose (zipWith replConsec b m))
{-# INLINE solve #-}
-- matrix inversion
invert !m = transpose (map (\v -> solve m v) identity)
{-# INLINE invert #-}
-- some functions for homogoneous coordinates
class HomogCoords a v where
homVec :: v -> (a:.v)
--Interpret the vector as a direction / point at infinity
homPoint :: v -> (a:.v)
--Interpret the vector as a point
project :: (a:.v) -> v
--Project a vector in homogenous coordinates back into "normal" space.
--It is assumed the last vector component is non-zero, ie it's a point.
instance
(Fractional a
,Num a
,Num v
,Fractional v
,Ord a
,Vec n a v
,Vec (Succ n) a (a:.v)
,Append v (a:.()) (a:.v)
,Take n a (a:.v) v
,Access n a (a:.v)
)
=> HomogCoords a v
where
homVec v = append v ((0::a):.()) :: (a:.v)
homPoint v = append v ((1::a):.()) :: (a:.v)
project v = (take (undefined::n) v) / (mkVec (undefined::n) $ get (undefined::n) v)
{-# INLINE homVec #-}
{-# INLINE homPoint #-}
{-# INLINE project #-}
-- apply a translation to a projective transformation matrix
translate v m =
case reverse (transpose m) of
(h:.t) -> transpose (reverse (((homVec v) + h) :. t))
{-# INLINE translate #-}
column n = get n . transpose
row n = get n
-- Storable instances.
instance Storable a => Storable (a:.()) where
sizeOf _ = sizeOf (undefined::a)
alignment _ = alignment (undefined::a)
peek !p = peek (castPtr p) >>= \a -> return (a:.())
peekByteOff !p !o = peek (p`plusPtr`o)
peekElemOff !p !i = peek (p`plusPtr`(i*sizeOf(undefined::a)))
poke !p !(a:._) = poke (castPtr p) a
pokeByteOff !p !o !x = poke (p`plusPtr`o) x
pokeElemOff !p !i !x = poke (p`plusPtr`(i*sizeOf(undefined::a))) x
{-# INLINE sizeOf #-}
{-# INLINE alignment #-}
{-# INLINE peek #-}
{-# INLINE peekByteOff #-}
{-# INLINE peekElemOff #-}
{-# INLINE poke #-}
{-# INLINE pokeByteOff #-}
{-# INLINE pokeElemOff #-}
instance (Vec (Succ n) a (a:.v), Storable a, Storable v) => Storable (a:.v)
where
sizeOf _ = sizeOf (undefined::a) + sizeOf (undefined::v)
alignment _ = alignment (undefined::a)
peek !p =
peek (castPtr p) >>= \a ->
peek (castPtr (p`plusPtr`sizeOf(undefined::a))) >>= \v ->
return (a:.v)
peekByteOff !p !o = peek (p`plusPtr`o)
peekElemOff !p !i = peek (p`plusPtr`(i*sizeOf(undefined::(a:.v))))
poke !p !(a:.v) =
poke (castPtr p) a >>
poke (castPtr (p`plusPtr`sizeOf(undefined::a))) v
pokeByteOff !p !o !x = poke (p`plusPtr`o) x
pokeElemOff !p !i !x = poke (p`plusPtr`(i*sizeOf(undefined::(a:.v)))) x
{-# INLINE sizeOf #-}
{-# INLINE alignment #-}
{-# INLINE peek #-}
{-# INLINE peekByteOff #-}
{-# INLINE peekElemOff #-}
{-# INLINE poke #-}
{-# INLINE pokeByteOff #-}
{-# INLINE pokeElemOff #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
module Test where
import Vec as V
data Vec3D = Vec3D {-#UNPACK#-} !Double
{-#UNPACK#-} !Double
{-#UNPACK#-} !Double
type Mat33D = Vec3 Vec3D
class PackedVec pv v | pv -> v where
packV :: v -> pv
unpackV :: pv -> v
instance PackedVec Vec3D (Vec3 Double) where
packV (x:.y:.z:.()) = Vec3D x y z
unpackV (Vec3D x y z) = x:.y:.z:.()
{-# INLINE packV #-}
{-# INLINE unpackV #-}
-- BUG IS HERE !!!
class (Map pv v pm m, Map v pv m pm, PackedVec pv v)
=> PackedMat pv v pm m | pv -> v, pm -> m
where
packM :: m -> pm
unpackM :: pm -> m
-- These default definitions are not inlined.
-- See instance declaration below.
packM = V.map packV
unpackM = V.map unpackV
{-# INLINE packM #-}
{-# INLINE unpackM #-}
-- BUG IS HERE !!!
instance PackedMat Vec3D (Vec3 Double) Mat33D (Mat33 Double)
-- Comment out these definitions to see the bug. Check core for
-- definition of multmv3d and notice call to unpackM, as well as many
-- unessecary constructors
where
packM = V.map packV
unpackM = V.map unpackV
{-# INLINE packM #-}
{-# INLINE unpackM #-}
-- Of course this suffices without the class:
{-
packM = V.map packV
unpackM = V.map unpackV
{-# INLINE packM #-}
{-# INLINE unpackM #-}
-}
addv3d :: Vec3D -> Vec3D -> Vec3D
addv3d a b = packV (unpackV a + unpackV b)
multmv3d :: Mat33D -> Vec3D -> Vec3D
multmv3d a b = packV $ unpackM a `multmv` unpackV b
_______________________________________________
Glasgow-haskell-users mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users