diff --git a/inline-r/inline-r.cabal b/inline-r/inline-r.cabal index 43b05135..f530fec1 100644 --- a/inline-r/inline-r.cabal +++ b/inline-r/inline-r.cabal @@ -47,7 +47,7 @@ source-repository head library exposed-modules: Control.Memory.Region --- Data.Vector.SEXP + Data.Vector.SEXP Data.Vector.SEXP.Base Data.Vector.SEXP.Mutable Foreign.R diff --git a/inline-r/src/Data/Vector/SEXP.hs b/inline-r/src/Data/Vector/SEXP.hs index 7060ef0e..70aea427 100644 --- a/inline-r/src/Data/Vector/SEXP.hs +++ b/inline-r/src/Data/Vector/SEXP.hs @@ -18,6 +18,7 @@ -- Note that since 'unstream' relies on slicing operations, it will still be an -- O(N) operation but it will copy vector data twice (instead of once). +{-# OPTIONS_GHC -fplugin-opt=LiquidHaskell:--skip-module=False #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} @@ -32,7 +33,10 @@ {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} +{-@ LIQUID "--exact-data-cons" @-} +{-@ LIQUID "--prune-unsorted" @-} module Data.Vector.SEXP +{- ( Vector(..) , Mutable.MVector(..) , ElemRep @@ -254,7 +258,7 @@ module Data.Vector.SEXP , toString , toByteString , unsafeWithByteString - ) where + ) -} where import Control.Exception (evaluate) import Control.Monad.R.Class @@ -296,12 +300,14 @@ import Control.Monad.Primitive ( PrimMonad, unsafeInlineIO, unsafePrimToPrim ) import qualified Control.DeepSeq as DeepSeq import Data.Word ( Word8 ) import Foreign ( Storable, Ptr, castPtr, peekElemOff ) +import Foreign.C.String -- XXX: Needed for LH name resolution import Foreign.ForeignPtr (ForeignPtr, withForeignPtr) import Foreign.Marshal.Array ( copyArray ) import qualified GHC.Foreign as GHC import qualified GHC.ForeignPtr as GHC import GHC.IO.Encoding.UTF8 import qualified GHC.Exts as Exts +import Internal.Error (violation) import System.IO.Unsafe import Prelude @@ -324,56 +330,58 @@ import Prelude ) import qualified Prelude -newtype ForeignSEXP (ty::SEXPTYPE) = ForeignSEXP (ForeignPtr R.SEXPREC) +newtype ForeignSEXP = ForeignSEXP (ForeignPtr R.SEXPREC) + +{-@ measure Data.Vector.SEXP.ftypeOf :: ForeignSEXP -> R.SEXPTYPE @-} -- | Create a 'ForeignSEXP' from 'SEXP'. -foreignSEXP :: PrimMonad m => SEXP s ty -> m (ForeignSEXP ty) +{-@ assume foreignSEXP :: s:SEXP s -> m {v:ForeignSEXP | Data.Vector.SEXP.ftypeOf v == typeOf s} @-} +foreignSEXP :: PrimMonad m => SEXP s -> m ForeignSEXP foreignSEXP sx@(SEXP (SEXP0 ptr)) = unsafePrimToPrim $ mask_ $ do R.preserveObject sx ForeignSEXP <$> GHC.newConcForeignPtr ptr (R.releaseObject sx) -withForeignSEXP - :: ForeignSEXP ty - -> (SEXP V ty -> IO r) - -> IO r +{-@ assume withForeignSEXP :: f:ForeignSEXP -> (TSEXP V (Data.Vector.SEXP.ftypeOf f) -> IO r) -> IO r @-} +withForeignSEXP :: ForeignSEXP -> (SEXP V -> IO r) -> IO r withForeignSEXP (ForeignSEXP fptr) f = withForeignPtr fptr $ \ptr -> f (SEXP (SEXP0 ptr)) --- | Immutable vectors. The second type paramater is a phantom parameter --- reflecting at the type level the tag of the vector when viewed as a 'SEXP'. --- The tag of the vector and the representation type are related via 'ElemRep'. -data Vector (ty :: SEXPTYPE) a = Vector - { vectorBase :: {-# UNPACK #-} !(ForeignSEXP ty) +{-@ measure Data.Vector.SEXP.vtypeOf :: Vector a -> R.SEXPTYPE @-} +{-@ type TVector a T = {v:Vector a | Data.Vector.SEXP.vtypeOf v == T} @-} + +-- | Immutable vectors. +data Vector a = Vector + { vectorBase :: {-# UNPACK #-} !ForeignSEXP , vectorOffset :: {-# UNPACK #-} !Int32 , vectorLength :: {-# UNPACK #-} !Int32 } -instance (Eq a, SVECTOR ty a) => Eq (Vector ty a) where +instance (Eq a, Storable a) => Eq (Vector a) where a == b = toList a == toList b -instance (Show a, SVECTOR ty a) => Show (Vector ty a) where +instance (Show a, Storable a) => Show (Vector a) where show v = "fromList " Prelude.++ showList (toList v) "" -- | Internal wrapper type for reflection. First type parameter is the reified -- type to reflect. -newtype W t ty a = W { unW :: Vector ty a } +newtype W t a = W { unW :: Vector a } -withW :: proxy t -> Vector ty a -> W t ty a +withW :: proxy t -> Vector a -> W t a withW _ v = W v -proxyFW :: (W t ty a -> r) -> Vector ty a -> p t -> r +proxyFW :: (W t a -> r) -> Vector a -> p t -> r proxyFW f v p = f (withW p v) -proxyFW2 :: (W t tya a -> W t tyb b -> r) -> Vector tya a -> Vector tyb b -> p t -> r +proxyFW2 :: (W t a -> W t b -> r) -> Vector a -> Vector b -> p t -> r proxyFW2 f v1 v2 p = f (withW p v1) (withW p v2) -proxyW :: W t ty a -> p t -> Vector ty a +proxyW :: W t a -> p t -> Vector a proxyW v _ = unW v -type instance G.Mutable (W t ty) = Mutable.W t ty +type instance G.Mutable (W t) = Mutable.W t -instance (Reifies t (AcquireIO s), SVECTOR ty a) => G.Vector (W t ty) a where +instance (Reifies t (AcquireIO s, IO R.SEXPTYPE), Storable a) => G.Vector (W t) a where {-# INLINE basicUnsafeFreeze #-} basicUnsafeFreeze (Mutable.unW -> Mutable.MVector sx off len) = do fp <- foreignSEXP sx @@ -384,7 +392,7 @@ instance (Reifies t (AcquireIO s), SVECTOR ty a) => G.Vector (W t ty) a where sx' <- acquireIO (R.release ptr) return $ Mutable.withW p $ Mutable.MVector (R.unsafeRelease sx') off len where - AcquireIO acquireIO = reflect (Proxy :: Proxy t) + (acquireIO, _) = reflect (Proxy :: Proxy t) p = Proxy :: Proxy t basicLength (unW -> Vector _ _ len) = fromIntegral len {-# INLINE basicUnsafeSlice #-} @@ -401,21 +409,27 @@ instance (Reifies t (AcquireIO s), SVECTOR ty a) => G.Vector (W t ty) a where {-# INLINE elemseq #-} elemseq _ = seq -instance SVECTOR ty a => Exts.IsList (Vector ty a) where - type Item (Vector ty a) = a - fromList = fromList - fromListN = fromListN - toList = toList +-- TODO: how to disable LH on a class instance? +-- instance Storable a => Exts.IsList (Vector a) where +-- type Item (Vector a) = a + -- TODO: How to disable LH so it doesn't complain of these methods calling error + -- fromList = Prelude.error "cannot convert list to vector without an explicit runtime type" + -- fromListN = Prelude.error "cannot convert list to vector without an explicit runtime type" + -- fromList = fromList + -- fromListN = fromListN +-- toList = toList -- | Return Pointer of the first element of the vector storage. -unsafeToPtr :: Storable a => Vector ty a -> Ptr a +unsafeToPtr :: Storable a => Vector a -> Ptr a {-# INLINE unsafeToPtr #-} unsafeToPtr (Vector fp off len) = unsafeInlineIO $ withForeignSEXP fp $ \sx -> return $ Mutable.unsafeToPtr $ Mutable.MVector sx off len -- | /O(n)/ Create an immutable vector from a 'SEXP'. Because 'SEXP's are -- mutable, this function yields an immutable /copy/ of the 'SEXP'. -fromSEXP :: (SVECTOR ty a) => SEXP s ty -> Vector ty a +{-@ assume fromSEXP :: {s:SEXP s | isVectorType (typeOf s)} -> {v:Vector a | Data.Vector.SEXP.vtypeOf v == typeOf s} @-} +{-@ ignore fromSEXP @-} +fromSEXP :: Storable a => SEXP s -> Vector a fromSEXP s = phony $ \p -> runST $ do w <- run (proxyFW G.clone (unsafeFromSEXP s) p) v <- G.unsafeFreeze w @@ -424,16 +438,19 @@ fromSEXP s = phony $ \p -> runST $ do -- | /O(1)/ Unsafe convert a mutable 'SEXP' to an immutable vector without -- copying. The mutable vector must not be used after this operation, lest one -- runs the risk of breaking referential transparency. -unsafeFromSEXP :: SVECTOR ty a - => SEXP s ty - -> Vector ty a +{-@ assume unsafeFromSEXP :: {s:SEXP s | isVectorType (typeOf s)} -> {v:Vector a | Data.Vector.SEXP.vtypeOf v == typeOf s} @-} +unsafeFromSEXP :: Storable a + => SEXP s + -> Vector a unsafeFromSEXP s = unsafeInlineIO $ do sxp <- foreignSEXP s l <- R.length s return $ Vector sxp 0 (fromIntegral l) -- | /O(n)/ Yield a (mutable) copy of the vector as a 'SEXP'. -toSEXP :: SVECTOR ty a => Vector ty a -> SEXP s ty + +{-@ assume toSEXP :: v:Vector a -> {s:SEXP s | typeOf s == Data.Vector.SEXP.vtypeOf v} @-} +toSEXP :: Storable a => Vector a -> SEXP s toSEXP s = phony $ \p -> runST $ do w <- run (proxyFW G.clone s p) v <- G.unsafeFreeze w @@ -441,18 +458,23 @@ toSEXP s = phony $ \p -> runST $ do -- | /O(1)/ Unsafely convert an immutable vector to a (mutable) 'SEXP' without -- copying. The immutable vector must not be used after this operation. -unsafeToSEXP :: SVECTOR ty a => Vector ty a -> SEXP s ty +{-@ assume unsafeToSEXP :: v:Vector a -> {s:SEXP s | typeOf s == Data.Vector.SEXP.vtypeOf v} @-} +unsafeToSEXP :: Storable a => Vector a -> SEXP s unsafeToSEXP (Vector (ForeignSEXP fsx) _ _) = unsafePerformIO $ -- XXX withForeignPtr fsx $ return . R.sexp . SEXP0 -- | /O(n)/ Convert a character vector into a 'String'. -toString :: Vector 'Char Word8 -> String +{-@ assume toString :: TVector Word8 Char -> String @-} +{-@ ignore toString @-} +toString :: Vector Word8 -> String toString v = unsafeInlineIO $ GHC.peekCStringLen utf8 ( castPtr $ unsafeToPtr v , fromIntegral $ vectorLength v) -- | /O(n)/ Convert a character vector into a strict 'ByteString'. -toByteString :: Vector 'Char Word8 -> ByteString +{-@ assume toByteString :: TVector Word8 Char -> ByteString @-} +{-@ ignore toByteString @-} +toByteString :: Vector Word8 -> ByteString toByteString v = unsafeInlineIO $ B.packCStringLen ( castPtr $ unsafeToPtr v , fromIntegral $ vectorLength v) @@ -461,12 +483,14 @@ toByteString v = unsafeInlineIO $ -- outside of the function. Any change to bytestring will be -- reflected in the source vector, thus breaking referencial -- transparancy. -unsafeWithByteString :: DeepSeq.NFData a => Vector 'Char Word8 -> (ByteString -> IO a) -> a +{-@ assume unsafeWithByteString :: TVector Word8 Char -> (ByteString -> IO a) -> a @-} +{-@ ignore unsafeWithByteString @-} +unsafeWithByteString :: DeepSeq.NFData a => Vector Word8 -> (ByteString -> IO a) -> a unsafeWithByteString v f = unsafeInlineIO $ do x <- B.unsafePackCStringLen (castPtr $ unsafeToPtr v ,fromIntegral $ vectorLength v) w <- DeepSeq.force <$> f x - evaluate w + evaluate w ------------------------------------------------------------------------ -- Vector API @@ -477,12 +501,12 @@ unsafeWithByteString v f = unsafeInlineIO $ do ------------------------------------------------------------------------ -- | /O(1)/ Yield the length of the vector. -length :: SVECTOR ty a => Vector ty a -> Int +length :: Storable a => Vector a -> Int {-# INLINE length #-} length v = phony $ proxyFW G.length v -- | /O(1)/ Test whether a vector if empty -null :: SVECTOR ty a => Vector ty a -> Bool +null :: Storable a => Vector a -> Bool {-# INLINE null #-} null v = phony $ proxyFW G.null v @@ -491,37 +515,37 @@ null v = phony $ proxyFW G.null v ------------------------------------------------------------------------ -- | O(1) Indexing -(!) :: SVECTOR ty a => Vector ty a -> Int -> a +(!) :: Storable a => Vector a -> Int -> a {-# INLINE (!) #-} (!) v i = phony $ proxyFW (G.! i) v -- | O(1) Safe indexing -(!?) :: SVECTOR ty a => Vector ty a -> Int -> Maybe a +(!?) :: Storable a => Vector a -> Int -> Maybe a {-# INLINE (!?) #-} (!?) v i = phony $ proxyFW (G.!? i) v -- | /O(1)/ First element -head :: SVECTOR ty a => Vector ty a -> a +head :: Storable a => Vector a -> a {-# INLINE head #-} head v = phony $ proxyFW G.head v -- | /O(1)/ Last element -last :: SVECTOR ty a => Vector ty a -> a +last :: Storable a => Vector a -> a {-# INLINE last #-} last v = phony $ proxyFW G.last v -- | /O(1)/ Unsafe indexing without bounds checking -unsafeIndex :: SVECTOR ty a => Vector ty a -> Int -> a +unsafeIndex :: Storable a => Vector a -> Int -> a {-# INLINE unsafeIndex #-} unsafeIndex v i = phony $ proxyFW (`G.unsafeIndex` i) v -- | /O(1)/ First element without checking if the vector is empty -unsafeHead :: SVECTOR ty a => Vector ty a -> a +unsafeHead :: Storable a => Vector a -> a {-# INLINE unsafeHead #-} unsafeHead v = phony $ proxyFW G.unsafeHead v -- | /O(1)/ Last element without checking if the vector is empty -unsafeLast :: SVECTOR ty a => Vector ty a -> a +unsafeLast :: Storable a => Vector a -> a {-# INLINE unsafeLast #-} unsafeLast v = phony $ proxyFW G.unsafeLast v @@ -548,37 +572,37 @@ unsafeLast v = phony $ proxyFW G.unsafeLast v -- Here, no references to @v@ are retained because indexing (but /not/ the -- elements) is evaluated eagerly. -- -indexM :: (SVECTOR ty a, Monad m) => Vector ty a -> Int -> m a +indexM :: (Storable a, Monad m) => Vector a -> Int -> m a {-# INLINE indexM #-} indexM v i = phony $ proxyFW (`G.indexM` i) v -- | /O(1)/ First element of a vector in a monad. See 'indexM' for an -- explanation of why this is useful. -headM :: (SVECTOR ty a, Monad m) => Vector ty a -> m a +headM :: (Storable a, Monad m) => Vector a -> m a {-# INLINE headM #-} headM v = phony $ proxyFW G.headM v -- | /O(1)/ Last element of a vector in a monad. See 'indexM' for an -- explanation of why this is useful. -lastM :: (SVECTOR ty a, Monad m) => Vector ty a -> m a +lastM :: (Storable a, Monad m) => Vector a -> m a {-# INLINE lastM #-} lastM v = phony $ proxyFW G.lastM v -- | /O(1)/ Indexing in a monad without bounds checks. See 'indexM' for an -- explanation of why this is useful. -unsafeIndexM :: (SVECTOR ty a, Monad m) => Vector ty a -> Int -> m a +unsafeIndexM :: (Storable a, Monad m) => Vector a -> Int -> m a {-# INLINE unsafeIndexM #-} unsafeIndexM v = phony $ proxyFW G.unsafeIndexM v -- | /O(1)/ First element in a monad without checking for empty vectors. -- See 'indexM' for an explanation of why this is useful. -unsafeHeadM :: (SVECTOR ty a, Monad m) => Vector ty a -> m a +unsafeHeadM :: (Storable a, Monad m) => Vector a -> m a {-# INLINE unsafeHeadM #-} unsafeHeadM v = phony $ proxyFW G.unsafeHeadM v -- | /O(1)/ Last element in a monad without checking for empty vectors. -- See 'indexM' for an explanation of why this is useful. -unsafeLastM :: (SVECTOR ty a, Monad m) => Vector ty a -> m a +unsafeLastM :: (Storable a, Monad m) => Vector a -> m a {-# INLINE unsafeLastM #-} unsafeLastM v = phony $ proxyFW G.unsafeLastM v @@ -588,34 +612,39 @@ unsafeLastM v = phony $ proxyFW G.unsafeLastM v -- | /O(N)/ Yield a slice of the vector with copying it. The vector must -- contain at least @i+n@ elements. -slice :: SVECTOR ty a +{-@ assume slice :: Int -> Int -> v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +slice :: Storable a => Int -- ^ @i@ starting index -> Int -- ^ @n@ length - -> Vector ty a - -> Vector ty a + -> Vector a + -> Vector a {-# INLINE slice #-} slice i n v = phony $ unW . proxyFW (G.slice i n) v -- | /O(N)/ Yield all but the last element, this operation will copy an array. -- The vector may not be empty. -init :: SVECTOR ty a => Vector ty a -> Vector ty a +{-@ assume init :: v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +init :: Storable a => Vector a -> Vector a {-# INLINE init #-} init v = phony $ unW . proxyFW G.init v -- | /O(N)/ Copy all but the first element. The vector may not be empty. -tail :: SVECTOR ty a => Vector ty a -> Vector ty a +{-@ assume tail :: v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +tail :: Storable a => Vector a -> Vector a {-# INLINE tail #-} tail v = phony $ unW . proxyFW G.tail v -- | /O(N)/ Yield at the first @n@ elements with copying. The vector may -- contain less than @n@ elements in which case it is returned unchanged. -take :: SVECTOR ty a => Int -> Vector ty a -> Vector ty a +{-@ assume take :: Int -> v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +take :: Storable a => Int -> Vector a -> Vector a {-# INLINE take #-} take i v = phony $ unW . proxyFW (G.take i) v -- | /O(N)/ Yield all but the first @n@ elements with copying. The vector may -- contain less than @n@ elements in which case an empty vector is returned. -drop :: SVECTOR ty a => Int -> Vector ty a -> Vector ty a +{-@ assume drop :: Int -> v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +drop :: Storable a => Int -> Vector a -> Vector a {-# INLINE drop #-} drop i v = phony $ unW . proxyFW (G.drop i) v @@ -623,40 +652,46 @@ drop i v = phony $ unW . proxyFW (G.drop i) v -- -- Note that @'splitAt' n v@ is equivalent to @('take' n v, 'drop' n v)@ -- but slightly more efficient. +{-@ assume splitAt :: Int -> v:Vector a -> (TVector a (Data.Vector.SEXP.vtypeOf v), TVector a (Data.Vector.SEXP.vtypeOf v)) @-} {-# INLINE splitAt #-} -splitAt :: SVECTOR ty a => Int -> Vector ty a -> (Vector ty a, Vector ty a) +splitAt :: Storable a => Int -> Vector a -> (Vector a, Vector a) splitAt i v = phony $ (\(a,b) -> (unW a, unW b)) . proxyFW (G.splitAt i) v -- | /O(N)/ Yield a slice of the vector with copying. The vector must -- contain at least @i+n@ elements but this is not checked. -unsafeSlice :: SVECTOR ty a => Int -- ^ @i@ starting index +{-@ assume unsafeSlice :: Int -> Int -> v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +unsafeSlice :: Storable a => Int -- ^ @i@ starting index -> Int -- ^ @n@ length - -> Vector ty a - -> Vector ty a + -> Vector a + -> Vector a {-# INLINE unsafeSlice #-} unsafeSlice i j v = phony $ unW . proxyFW (G.unsafeSlice i j) v -- | /O(N)/ Yield all but the last element with copying. The vector may not -- be empty but this is not checked. -unsafeInit :: SVECTOR ty a => Vector ty a -> Vector ty a +{-@ assume unsafeInit :: v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +unsafeInit :: Storable a => Vector a -> Vector a {-# INLINE unsafeInit #-} unsafeInit v = phony $ unW . proxyFW G.unsafeInit v -- | /O(N)/ Yield all but the first element with copying. The vector may not -- be empty but this is not checked. -unsafeTail :: SVECTOR ty a => Vector ty a -> Vector ty a +{-@ assume unsafeTail :: v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +unsafeTail :: Storable a => Vector a -> Vector a {-# INLINE unsafeTail #-} unsafeTail v = phony $ unW . proxyFW G.unsafeTail v -- | /O(N)/ Yield the first @n@ elements with copying. The vector must -- contain at least @n@ elements but this is not checked. -unsafeTake :: SVECTOR ty a => Int -> Vector ty a -> Vector ty a +{-@ assume unsafeTake :: Int -> v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +unsafeTake :: Storable a => Int -> Vector a -> Vector a {-# INLINE unsafeTake #-} unsafeTake i v = phony $ unW . proxyFW (G.unsafeTake i) v -- | /O(N)/ Yield all but the first @n@ elements with copying. The vector -- must contain at least @n@ elements but this is not checked. -unsafeDrop :: SVECTOR ty a => Int -> Vector ty a -> Vector ty a +{-@ assume unsafeDrop :: Int -> v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +unsafeDrop :: Storable a => Int -> Vector a -> Vector a {-# INLINE unsafeDrop #-} unsafeDrop i v = phony $ unW . proxyFW (G.unsafeDrop i) v @@ -664,30 +699,35 @@ unsafeDrop i v = phony $ unW . proxyFW (G.unsafeDrop i) v -- -------------- -- | /O(1)/ Empty vector -empty :: SVECTOR ty a => Vector ty a +{-@ assume empty :: x:VSEXPTYPE s a -> TVector a (vstypeOf x) @-} +empty :: Storable a => VSEXPTYPE s a -> Vector a {-# INLINE empty #-} -empty = phony $ proxyW G.empty +empty t = phonyvtype t $ proxyW G.empty -- | /O(1)/ Vector with exactly one element -singleton :: SVECTOR ty a => a -> Vector ty a +{-@ assume singleton :: x:VSEXPTYPE s a -> a -> TVector a (vstypeOf x) @-} +singleton :: Storable a => VSEXPTYPE s a -> a -> Vector a {-# INLINE singleton #-} -singleton a = phony $ proxyW (G.singleton a) +singleton t a = phonyvtype t $ proxyW (G.singleton a) -- | /O(n)/ Vector of the given length with the same value in each position -replicate :: SVECTOR ty a => Int -> a -> Vector ty a +{-@ assume replicate :: x:VSEXPTYPE s a -> Int -> a -> TVector a (vstypeOf x) @-} +replicate :: Storable a => VSEXPTYPE s a -> Int -> a -> Vector a {-# INLINE replicate #-} -replicate i v = phony $ proxyW (G.replicate i v) +replicate t i v = phonyvtype t $ proxyW (G.replicate i v) -- | /O(n)/ Construct a vector of the given length by applying the function to -- each index -generate :: SVECTOR ty a => Int -> (Int -> a) -> Vector ty a +{-@ assume generate :: x:VSEXPTYPE s a -> Int -> (Int -> a) -> TVector a (vstypeOf x) @-} +generate :: Storable a => VSEXPTYPE s a -> Int -> (Int -> a) -> Vector a {-# INLINE generate #-} -generate i f = phony $ proxyW (G.generate i f) +generate t i f = phonyvtype t $ proxyW (G.generate i f) -- | /O(n)/ Apply function n times to value. Zeroth element is original value. -iterateN :: SVECTOR ty a => Int -> (a -> a) -> a -> Vector ty a +{-@ assume iterateN :: x:VSEXPTYPE s a -> Int -> (a -> a) -> a -> TVector a (vstypeOf x) @-} +iterateN :: Storable a => VSEXPTYPE s a -> Int -> (a -> a) -> a -> Vector a {-# INLINE iterateN #-} -iterateN i f a = phony $ proxyW (G.iterateN i f a) +iterateN t i f a = phonyvtype t $ proxyW (G.iterateN i f a) -- Unfolding -- --------- @@ -697,27 +737,30 @@ iterateN i f a = phony $ proxyW (G.iterateN i f a) -- -- > unfoldr (\n -> if n == 0 then Nothing else Just (n,n-1)) 10 -- > = <10,9,8,7,6,5,4,3,2,1> -unfoldr :: SVECTOR ty a => (b -> Maybe (a, b)) -> b -> Vector ty a +{-@ assume unfoldr :: x:VSEXPTYPE s a -> (b -> Maybe (a, b)) -> b -> TVector a (vstypeOf x) @-} +unfoldr :: Storable a => VSEXPTYPE s a -> (b -> Maybe (a, b)) -> b -> Vector a {-# INLINE unfoldr #-} -unfoldr g a = phony $ proxyW (G.unfoldr g a) +unfoldr t g a = phonyvtype t $ proxyW (G.unfoldr g a) -- | /O(n)/ Construct a vector with at most @n@ by repeatedly applying the -- generator function to the a seed. The generator function yields 'Just' the -- next element and the new seed or 'Nothing' if there are no more elements. -- -- > unfoldrN 3 (\n -> Just (n,n-1)) 10 = <10,9,8> -unfoldrN :: SVECTOR ty a => Int -> (b -> Maybe (a, b)) -> b -> Vector ty a +{-@ assume unfoldrN :: x:VSEXPTYPE s a -> Int -> (b -> Maybe (a, b)) -> b -> TVector a (vstypeOf x) @-} +unfoldrN :: Storable a => VSEXPTYPE s a -> Int -> (b -> Maybe (a, b)) -> b -> Vector a {-# INLINE unfoldrN #-} -unfoldrN n g a = phony $ proxyW (G.unfoldrN n g a) +unfoldrN t n g a = phonyvtype t $ proxyW (G.unfoldrN n g a) -- | /O(n)/ Construct a vector with @n@ elements by repeatedly applying the -- generator function to the already constructed part of the vector. -- -- > constructN 3 f = let a = f <> ; b = f ; c = f in f -- -constructN :: SVECTOR ty a => Int -> (Vector ty a -> a) -> Vector ty a +{-@ assume constructN :: x:VSEXPTYPE s a -> Int -> (TVector a (vstypeOf x) -> a) -> TVector a (vstypeOf x) @-} +constructN :: Storable a => VSEXPTYPE s a -> Int -> (Vector a -> a) -> Vector a {-# INLINE constructN #-} -constructN n g = phony $ proxyW (G.constructN n (g.unW)) +constructN t n g = phonyvtype t $ proxyW (G.constructN n (g.unW)) -- | /O(n)/ Construct a vector with @n@ elements from right to left by -- repeatedly applying the generator function to the already constructed part @@ -725,9 +768,10 @@ constructN n g = phony $ proxyW (G.constructN n (g.unW)) -- -- > constructrN 3 f = let a = f <> ; b = f ; c = f in f -- -constructrN :: SVECTOR ty a => Int -> (Vector ty a -> a) -> Vector ty a +{-@ assume constructrN :: x:VSEXPTYPE s a -> Int -> (TVector a (vstypeOf x) -> a) -> TVector a (vstypeOf x) @-} +constructrN :: Storable a => VSEXPTYPE s a -> Int -> (Vector a -> a) -> Vector a {-# INLINE constructrN #-} -constructrN n g = phony $ proxyW (G.constructrN n (g.unW)) +constructrN t n g = phonyvtype t $ proxyW (G.constructrN n (g.unW)) -- Enumeration -- ----------- @@ -736,82 +780,93 @@ constructrN n g = phony $ proxyW (G.constructrN n (g.unW)) -- etc. This operation is usually more efficient than 'enumFromTo'. -- -- > enumFromN 5 3 = <5,6,7> -enumFromN :: (SVECTOR ty a, Num a) => a -> Int -> Vector ty a +{-@ assume enumFromN :: x:VSEXPTYPE s a -> a -> Int -> TVector a (vstypeOf x) @-} +enumFromN :: (Storable a, Num a) => VSEXPTYPE s a -> a -> Int -> Vector a {-# INLINE enumFromN #-} -enumFromN a i = phony $ proxyW (G.enumFromN a i) +enumFromN t a i = phonyvtype t $ proxyW (G.enumFromN a i) -- | /O(n)/ Yield a vector of the given length containing the values @x@, @x+y@, -- @x+y+y@ etc. This operations is usually more efficient than 'enumFromThenTo'. -- -- > enumFromStepN 1 0.1 5 = <1,1.1,1.2,1.3,1.4> -enumFromStepN :: (SVECTOR ty a, Num a) => a -> a -> Int -> Vector ty a +{-@ assume enumFromStepN :: x:VSEXPTYPE s a -> a -> a -> Int -> TVector a (vstypeOf x) @-} +enumFromStepN :: (Storable a, Num a) => VSEXPTYPE s a -> a -> a -> Int -> Vector a {-# INLINE enumFromStepN #-} -enumFromStepN f t s = phony $ proxyW (G.enumFromStepN f t s) +enumFromStepN vt f t s = phonyvtype vt $ proxyW (G.enumFromStepN f t s) -- | /O(n)/ Enumerate values from @x@ to @y@. -- -- /WARNING:/ This operation can be very inefficient. If at all possible, use -- 'enumFromN' instead. -enumFromTo :: (SVECTOR ty a, Enum a) => a -> a -> Vector ty a +{-@ assume enumFromTo :: x:VSEXPTYPE s a -> a -> a -> TVector a (vstypeOf x) @-} +enumFromTo :: (Storable a, Enum a) => VSEXPTYPE s a -> a -> a -> Vector a {-# INLINE enumFromTo #-} -enumFromTo f t = phony $ proxyW (G.enumFromTo f t) +enumFromTo vt f t = phonyvtype vt $ proxyW (G.enumFromTo f t) -- | /O(n)/ Enumerate values from @x@ to @y@ with a specific step @z@. -- -- /WARNING:/ This operation can be very inefficient. If at all possible, use -- 'enumFromStepN' instead. -enumFromThenTo :: (SVECTOR ty a, Enum a) => a -> a -> a -> Vector ty a +{-@ assume enumFromThenTo :: x:VSEXPTYPE s a -> a -> a -> a -> TVector a (vstypeOf x) @-} +enumFromThenTo :: (Storable a, Enum a) => VSEXPTYPE s a -> a -> a -> a -> Vector a {-# INLINE enumFromThenTo #-} -enumFromThenTo f t s = phony $ proxyW (G.enumFromThenTo f t s) +enumFromThenTo vt f t s = phonyvtype vt $ proxyW (G.enumFromThenTo f t s) -- Concatenation -- ------------- -- | /O(n)/ Prepend an element -cons :: SVECTOR ty a => a -> Vector ty a -> Vector ty a +{-@ assume cons :: a -> v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +cons :: Storable a => a -> Vector a -> Vector a {-# INLINE cons #-} cons a v = phony $ unW . proxyFW (G.cons a) v -- | /O(n)/ Append an element -snoc :: SVECTOR ty a => Vector ty a -> a -> Vector ty a +{-@ assume snoc :: v:Vector a -> a -> TVector a (Data.Vector.SEXP.vtypeOf v) @-} +snoc :: Storable a => Vector a -> a -> Vector a {-# INLINE snoc #-} snoc v a = phony $ unW . proxyFW (`G.snoc` a) v infixr 5 ++ -- | /O(m+n)/ Concatenate two vectors -(++) :: SVECTOR ty a => Vector ty a -> Vector ty a -> Vector ty a +{-@ assume (++) :: x:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf x) -> TVector a (Data.Vector.SEXP.vtypeOf x) @-} +(++) :: Storable a => Vector a -> Vector a -> Vector a {-# INLINE (++) #-} v1 ++ v2 = phony $ unW . proxyFW2 (G.++) v1 v2 -- | /O(n)/ Concatenate all vectors in the list -concat :: SVECTOR ty a => [Vector ty a] -> Vector ty a +{-@ assume concat :: x:VSEXPTYPE s a -> [TVector a (vstypeOf x)] -> TVector a (vstypeOf x) @-} +concat :: Storable a => VSEXPTYPE s a -> [Vector a] -> Vector a {-# INLINE concat #-} -concat vs = phony $ \p -> unW $ G.concat $ Prelude.map (withW p) vs +concat t vs = phonyvtype t $ \p -> unW $ G.concat $ Prelude.map (withW p) vs -- Monadic initialisation -- ---------------------- -- | /O(n)/ Execute the monadic action the given number of times and store the -- results in a vector. -replicateM :: (Monad m, SVECTOR ty a) => Int -> m a -> m (Vector ty a) +{-@ assume replicateM :: x:VSEXPTYPE s a -> Int -> m a -> m (TVector a (vstypeOf x)) @-} +replicateM :: (Monad m, Storable a) => VSEXPTYPE s a -> Int -> m a -> m (Vector a) {-# INLINE replicateM #-} -replicateM n f = phony $ \p -> (\v -> proxyW v p) <$> G.replicateM n f +replicateM t n f = phonyvtype t $ \p -> (\v -> proxyW v p) <$> G.replicateM n f -- | /O(n)/ Construct a vector of the given length by applying the monadic -- action to each index -generateM :: (Monad m, SVECTOR ty a) => Int -> (Int -> m a) -> m (Vector ty a) +{-@ assume generateM :: x:VSEXPTYPE s a -> Int -> (Int -> m a) -> m (TVector a (vstypeOf x)) @-} +generateM :: (Monad m, Storable a) => VSEXPTYPE s a -> Int -> (Int -> m a) -> m (Vector a) {-# INLINE generateM #-} -generateM n f = phony $ \p -> (\v -> proxyW v p) <$> G.generateM n f +generateM t n f = phonyvtype t $ \p -> (\v -> proxyW v p) <$> G.generateM n f -- | Execute the monadic action and freeze the resulting vector. -- -- @ -- create (do { v \<- new 2; write v 0 \'a\'; write v 1 \'b\'; return v }) = \<'a','b'\> -- @ -create :: SVECTOR ty a => (forall r. ST r (MVector r ty a)) -> Vector ty a +{-@ assume create :: x:VSEXPTYPE s a -> (forall r. ST r (TMVector r a (vstypeOf x))) -> TVector a (vstypeOf x) @-} +create :: Storable a => VSEXPTYPE s a -> (forall r. ST r (MVector r a)) -> Vector a {-# INLINE create #-} -- NOTE: eta-expanded due to http://hackage.haskell.org/trac/ghc/ticket/4120 -create f = phony $ \p -> unW $ G.create (Mutable.withW p <$> f) +create t f = phonyvtype t $ \p -> unW $ G.create (Mutable.withW p <$> f) -- Restricting memory usage -- ------------------------ @@ -826,7 +881,9 @@ create f = phony $ \p -> unW $ G.create (Mutable.withW p <$> f) -- Here, the slice retains a reference to the huge vector. Forcing it creates -- a copy of just the elements that belong to the slice and allows the huge -- vector to be garbage collected. -force :: SVECTOR ty a => Vector ty a -> Vector ty a + +{-@ assume force :: x:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf x) @-} +force :: Storable a => Vector a -> Vector a {-# INLINE force #-} force v = phony $ unW . proxyFW G.force v @@ -838,10 +895,11 @@ force v = phony $ unW . proxyFW G.force v -- -- > <5,9,2,7> // [(2,1),(0,3),(2,8)] = <3,9,8,7> -- -(//) :: SVECTOR ty a - => Vector ty a -- ^ initial vector (of length @m@) +{-@ assume (//) :: x:Vector a -> [(Int, a)] -> TVector a (Data.Vector.SEXP.vtypeOf x) @-} +(//) :: Storable a + => Vector a -- ^ initial vector (of length @m@) -> [(Int, a)] -- ^ list of index/value pairs (of length @n@) - -> Vector ty a + -> Vector a {-# INLINE (//) #-} (//) v l = phony $ unW . proxyFW (G.// l) v @@ -862,7 +920,8 @@ update_ = G.update_ -} -- | Same as ('//') but without bounds checking. -unsafeUpd :: SVECTOR ty a => Vector ty a -> [(Int, a)] -> Vector ty a +{-@ assume unsafeUpd :: x:Vector a -> [(Int, a)] -> TVector a (Data.Vector.SEXP.vtypeOf x) @-} +unsafeUpd :: Storable a => Vector a -> [(Int, a)] -> Vector a {-# INLINE unsafeUpd #-} unsafeUpd v l = phony $ unW . proxyFW (`G.unsafeUpd` l) v @@ -880,11 +939,12 @@ unsafeUpdate_ = G.unsafeUpdate_ -- @a@ at position @i@ by @f a b@. -- -- > accum (+) <5,9,2> [(2,4),(1,6),(0,3),(1,7)] = <5+3, 9+6+7, 2+4> -accum :: SVECTOR ty a +{-@ assume accum :: (a -> b -> a) -> x:Vector a -> [(Int,b)] -> TVector a (Data.Vector.SEXP.vtypeOf x) @-} +accum :: Storable a => (a -> b -> a) -- ^ accumulating function @f@ - -> Vector ty a -- ^ initial vector (of length @m@) + -> Vector a -- ^ initial vector (of length @m@) -> [(Int,b)] -- ^ list of index/value pairs (of length @n@) - -> Vector ty a + -> Vector a {-# INLINE accum #-} accum f v l = phony $ unW . proxyFW (\w -> G.accum f w l) v @@ -907,7 +967,8 @@ accumulate_ = G.accumulate_ -} -- | Same as 'accum' but without bounds checking. -unsafeAccum :: SVECTOR ty a => (a -> b -> a) -> Vector ty a -> [(Int,b)] -> Vector ty a +{-@ assume unsafeAccum :: (a -> b -> a) -> x:Vector a -> [(Int,b)] -> TVector a (Data.Vector.SEXP.vtypeOf x) @-} +unsafeAccum :: Storable a => (a -> b -> a) -> Vector a -> [(Int,b)] -> Vector a {-# INLINE unsafeAccum #-} unsafeAccum f v l = phony $ unW . proxyFW (\w -> G.unsafeAccum f w l) v @@ -923,7 +984,8 @@ unsafeAccumulate_ = G.unsafeAccumulate_ -- ------------ -- | /O(n)/ Reverse a vector -reverse :: SVECTOR ty a => Vector ty a -> Vector ty a +{-@ assume reverse :: x:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf x) @-} +reverse :: Storable a => Vector a -> Vector a {-# INLINE reverse #-} reverse v = phony $ unW . proxyFW G.reverse v @@ -965,24 +1027,27 @@ modify p = G.modify p -- ------- -- | /O(n)/ Map a function over a vector -map :: (SVECTOR ty a, SVECTOR ty b) => (a -> b) -> Vector ty a -> Vector ty b +{-@ assume map :: (a -> b) -> x:Vector a -> TVector b (Data.Vector.SEXP.vtypeOf x) @-} +map :: (Storable a, Storable b) => (a -> b) -> Vector a -> Vector b {-# INLINE map #-} map f v = phony $ unW . proxyFW (G.map f) v -- | /O(n)/ Apply a function to every element of a Vector ty and its index -imap :: (SVECTOR ty a, SVECTOR ty b) => (Int -> a -> b) -> Vector ty a -> Vector ty b +{-@ assume imap :: (Int -> a -> b) -> x:Vector a -> TVector b (Data.Vector.SEXP.vtypeOf x) @-} +imap :: (Storable a, Storable b) => (Int -> a -> b) -> Vector a -> Vector b {-# INLINE imap #-} imap f v = phony $ unW . proxyFW (G.imap f) v - -- | Map a function over a Vector ty and concatenate the results. -concatMap :: (SVECTOR tya a, SVECTOR tyb b) - => (a -> Vector tyb b) - -> Vector tya a - -> Vector tyb b +{-@ assume concatMap :: x:VSEXPTYPE s b -> (a -> TVector b (vstypeOf x)) -> Vector a -> TVector b (vstypeOf x) @-} +concatMap :: (Storable a, Storable b) + => VSEXPTYPE s b + -> (a -> Vector b) + -> Vector a + -> Vector b {-# INLINE concatMap #-} #if MIN_VERSION_vector(0,11,0) -concatMap f v = phony $ \p -> +concatMap t f v = phonyvtype t $ \p -> let v' = G.stream (withW p v) in proxyW (G.unstream $ Bundle.fromStream (Stream.concatMap (sElems . G.stream . withW p . f) (sElems v')) Unknown) p #else @@ -1000,25 +1065,29 @@ concatMap f v = -- | /O(n)/ Apply the monadic action to all elements of the vector, yielding a -- vector of results -mapM :: (Monad m, SVECTOR ty a, SVECTOR ty b) => (a -> m b) -> Vector ty a -> m (Vector ty b) +{-@ assume mapM :: (a -> m b) -> x:Vector a -> m (TVector b (Data.Vector.SEXP.vtypeOf x)) @-} +mapM :: (Monad m, Storable a, Storable b) => (a -> m b) -> Vector a -> m (Vector b) {-# INLINE mapM #-} mapM f v = phony $ \p -> unW <$> proxyFW (G.mapM f) v p -- | /O(n)/ Apply the monadic action to all elements of a Vector ty and ignore the -- results -mapM_ :: (Monad m, SVECTOR ty a) => (a -> m b) -> Vector ty a -> m () +{-@ mapM_ :: (a -> m b) -> Vector a -> m () @-} +mapM_ :: (Monad m, Storable a) => (a -> m b) -> Vector a -> m () {-# INLINE mapM_ #-} mapM_ f v = phony $ proxyFW (G.mapM_ f) v -- | /O(n)/ Apply the monadic action to all elements of the vector, yielding a -- vector of results. Equvalent to @flip 'mapM'@. -forM :: (Monad m, SVECTOR ty a, SVECTOR ty b) => Vector ty a -> (a -> m b) -> m (Vector ty b) +{-@ assume forM :: x:Vector a -> (a -> m b) -> m (TVector b (Data.Vector.SEXP.vtypeOf x)) @-} +forM :: (Monad m, Storable a, Storable b) => Vector a -> (a -> m b) -> m (Vector b) {-# INLINE forM #-} forM v f = phony $ \p -> unW <$> proxyFW (`G.forM` f) v p -- | /O(n)/ Apply the monadic action to all elements of a Vector ty and ignore the -- results. Equivalent to @flip 'mapM_'@. -forM_ :: (Monad m, SVECTOR ty a) => Vector ty a -> (a -> m b) -> m () +{-@ assume forM_ :: Vector a -> (a -> m b) -> m () @-} +forM_ :: (Monad m, Storable a) => Vector a -> (a -> m b) -> m () {-# INLINE forM_ #-} forM_ v f = phony $ proxyFW (`G.forM_` f) v @@ -1030,42 +1099,57 @@ smallest = List.foldl1' smaller #endif -- | /O(min(m,n))/ Zip two vectors with the given function. -zipWith :: (SVECTOR tya a, SVECTOR tyb b, SVECTOR tyc c) - => (a -> b -> c) -> Vector tya a -> Vector tyb b -> Vector tyc c +{-@ +assume zipWith + :: x:VSEXPTYPE s c -> (a -> b -> c) -> Vector a -> Vector b -> TVector c (vstypeOf x) +@-} +zipWith :: (Storable a, Storable b, Storable c) + => VSEXPTYPE s c -> (a -> b -> c) -> Vector a -> Vector b -> Vector c {-# INLINE zipWith #-} #if MIN_VERSION_vector(0,11,0) -zipWith f xs ys = phony $ \p -> +zipWith t f xs ys = phonyvtype t $ \p -> let xs' = G.stream (withW p xs) ys' = G.stream (withW p ys) sz = smaller (sSize xs') (sSize ys') in proxyW (G.unstream $ Bundle.fromStream (Stream.zipWith f (sElems xs') (sElems ys')) sz) p #else -zipWith f xs ys = phony $ \p -> +zipWith t f xs ys = phonyvtype t $ \p -> proxyW (G.unstream (Stream.zipWith f (G.stream (withW p xs)) (G.stream (withW p ys)))) p #endif -- | Zip three vectors with the given function. -zipWith3 :: (SVECTOR tya a, SVECTOR tyb b, SVECTOR tyc c, SVECTOR tyd d) - => (a -> b -> c -> d) -> Vector tya a -> Vector tyb b -> Vector tyc c -> Vector tyd d +{-@ +assume zipWith3 + :: x:VSEXPTYPE s d -> (a -> b -> c -> d) -> Vector a -> Vector b -> Vector c -> TVector d (vstypeOf x) +@-} +zipWith3 :: (Storable a, Storable b, Storable c, Storable d) + => VSEXPTYPE s d -> (a -> b -> c -> d) -> Vector a -> Vector b -> Vector c -> Vector d {-# INLINE zipWith3 #-} #if MIN_VERSION_vector(0,11,0) -zipWith3 f as bs cs = phony $ \p -> +zipWith3 t f as bs cs = phonyvtype t $ \p -> let as' = G.stream (withW p as) bs' = G.stream (withW p bs) cs' = G.stream (withW p cs) sz = smallest [sSize as', sSize bs', sSize cs'] in proxyW (G.unstream $ Bundle.fromStream (Stream.zipWith3 f (sElems as') (sElems bs') (sElems cs')) sz) p #else -zipWith3 f as bs cs = phony $ \p -> +zipWith3 t f as bs cs = phonyvtype t $ \p -> proxyW (G.unstream (Stream.zipWith3 f (G.stream (withW p as)) (G.stream (withW p bs)) (G.stream (withW p cs)))) p #endif -zipWith4 :: (SVECTOR tya a, SVECTOR tyb b, SVECTOR tyc c, SVECTOR tyd d, SVECTOR tye e) - => (a -> b -> c -> d -> e) - -> Vector tya a -> Vector tyb b -> Vector tyc c -> Vector tyd d -> Vector tye e +{-@ +assume zipWith4 + :: x:VSEXPTYPE s e + -> (a -> b -> c -> d -> e) + -> Vector a -> Vector b -> Vector c -> Vector d -> TVector e (vstypeOf x) +@-} +zipWith4 :: (Storable a, Storable b, Storable c, Storable d, Storable e) + => VSEXPTYPE s e + -> (a -> b -> c -> d -> e) + -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e {-# INLINE zipWith4 #-} #if MIN_VERSION_vector(0,11,0) -zipWith4 f as bs cs ds = phony $ \p -> +zipWith4 t f as bs cs ds = phonyvtype t $ \p -> let as' = G.stream (withW p as) bs' = G.stream (withW p bs) cs' = G.stream (withW p cs) @@ -1073,18 +1157,25 @@ zipWith4 f as bs cs ds = phony $ \p -> sz = smallest [sSize as', sSize bs', sSize cs', sSize ds'] in proxyW (G.unstream $ Bundle.fromStream (Stream.zipWith4 f (sElems as') (sElems bs') (sElems cs') (sElems ds')) sz) p #else -zipWith4 f as bs cs ds = phony $ \p -> +zipWith4 t f as bs cs ds = phonyvtype t $ \p -> proxyW (G.unstream (Stream.zipWith4 f (G.stream (withW p as)) (G.stream (withW p bs)) (G.stream (withW p cs)) (G.stream (withW p ds)))) p #endif -zipWith5 :: (SVECTOR tya a, SVECTOR tyb b, SVECTOR tyc c, SVECTOR tyd d, SVECTOR tye e, - SVECTOR tyf f) - => (a -> b -> c -> d -> e -> f) - -> Vector tya a -> Vector tyb b -> Vector tyc c -> Vector tyd d -> Vector tye e - -> Vector tyf f +{-@ +assume zipWith5 :: x:VSEXPTYPE s f + -> (a -> b -> c -> d -> e -> f) + -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e + -> TVector f (vstypeOf x) +@-} +zipWith5 :: (Storable a, Storable b, Storable c, Storable d, Storable e, + Storable f) + => VSEXPTYPE s f + -> (a -> b -> c -> d -> e -> f) + -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e + -> Vector f {-# INLINE zipWith5 #-} #if MIN_VERSION_vector(0,11,0) -zipWith5 f as bs cs ds es = phony $ \p -> +zipWith5 t f as bs cs ds es = phonyvtype t $ \p -> let as' = G.stream (withW p as) bs' = G.stream (withW p bs) cs' = G.stream (withW p cs) @@ -1093,18 +1184,25 @@ zipWith5 f as bs cs ds es = phony $ \p -> sz = smallest [sSize as', sSize bs', sSize cs', sSize ds', sSize es'] in proxyW (G.unstream $ Bundle.fromStream (Stream.zipWith5 f (sElems as') (sElems bs') (sElems cs') (sElems ds') (sElems es')) sz) p #else -zipWith5 f as bs cs ds es = phony $ \p -> +zipWith5 t f as bs cs ds es = phonyvtype t $ \p -> proxyW (G.unstream (Stream.zipWith5 f (G.stream (withW p as)) (G.stream (withW p bs)) (G.stream (withW p cs)) (G.stream (withW p ds)) (G.stream (withW p es)))) p #endif -zipWith6 :: (SVECTOR tya a, SVECTOR tyb b, SVECTOR tyc c, SVECTOR tyd d, SVECTOR tye e, - SVECTOR tyf f, SVECTOR tyg g) - => (a -> b -> c -> d -> e -> f -> g) - -> Vector tya a -> Vector tyb b -> Vector tyc c -> Vector tyd d -> Vector tye e - -> Vector tyf f -> Vector tyg g +{-@ +assume zipWith6 :: x:VSEXPTYPE s g + -> (a -> b -> c -> d -> e -> f -> g) + -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e + -> Vector f -> TVector g (vstypeOf x) +@-} +zipWith6 :: (Storable a, Storable b, Storable c, Storable d, Storable e, + Storable f, Storable g) + => VSEXPTYPE s g + -> (a -> b -> c -> d -> e -> f -> g) + -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e + -> Vector f -> Vector g {-# INLINE zipWith6 #-} #if MIN_VERSION_vector(0,11,0) -zipWith6 f as bs cs ds es fs = phony $ \p -> +zipWith6 t f as bs cs ds es fs = phonyvtype t $ \p -> let as' = G.stream (withW p as) bs' = G.stream (withW p bs) cs' = G.stream (withW p cs) @@ -1114,49 +1212,65 @@ zipWith6 f as bs cs ds es fs = phony $ \p -> sz = smallest [sSize as', sSize bs', sSize cs', sSize ds', sSize es', sSize fs'] in proxyW (G.unstream $ Bundle.fromStream (Stream.zipWith6 f (sElems as') (sElems bs') (sElems cs') (sElems ds') (sElems es') (sElems fs')) sz) p #else -zipWith6 f as bs cs ds es fs = phony $ \p -> +zipWith6 t f as bs cs ds es fs = phonyvtype t $ \p -> proxyW (G.unstream (Stream.zipWith6 f (G.stream (withW p as)) (G.stream (withW p bs)) (G.stream (withW p cs)) (G.stream (withW p ds)) (G.stream (withW p es)) (G.stream (withW p fs)))) p #endif -- | /O(min(m,n))/ Zip two vectors with a function that also takes the -- elements' indices. -izipWith :: (SVECTOR tya a, SVECTOR tyb b, SVECTOR tyc c) - => (Int -> a -> b -> c) -> Vector tya a -> Vector tyb b -> Vector tyc c +{-@ +assume izipWith + :: x:VSEXPTYPE s c -> (Int -> a -> b -> c) -> Vector a -> Vector b -> TVector c (vstypeOf x) +@-} +izipWith :: (Storable a, Storable b, Storable c) + => VSEXPTYPE s c -> (Int -> a -> b -> c) -> Vector a -> Vector b -> Vector c {-# INLINE izipWith #-} #if MIN_VERSION_vector(0,11,0) -izipWith f as bs = phony $ \p -> +izipWith t f as bs = phonyvtype t $ \p -> let as' = G.stream (withW p as) bs' = G.stream (withW p bs) sz = smaller (sSize as') (sSize bs') in proxyW (G.unstream $ Bundle.fromStream (Stream.zipWith (uncurry f) (Stream.indexed (sElems as')) (sElems bs')) sz) p #else -izipWith f as bs = phony $ \p -> +izipWith t f as bs = phonyvtype t $ \p -> proxyW (G.unstream (Stream.zipWith (uncurry f) (Stream.indexed (G.stream (withW p as))) (G.stream (withW p bs)))) p #endif -- | Zip three vectors and their indices with the given function. -izipWith3 :: (SVECTOR tya a, SVECTOR tyb b, SVECTOR tyc c, SVECTOR tyd d) - => (Int -> a -> b -> c -> d) - -> Vector tya a -> Vector tyb b -> Vector tyc c -> Vector tyd d +{-@ +assume izipWith3 + :: x:VSEXPTYPE s d -> (Int -> a -> b -> c -> d) -> Vector a -> Vector b -> Vector c -> TVector d (vstypeOf x) +@-} +izipWith3 :: (Storable a, Storable b, Storable c, Storable d) + => VSEXPTYPE s d + -> (Int -> a -> b -> c -> d) + -> Vector a -> Vector b -> Vector c -> Vector d {-# INLINE izipWith3 #-} #if MIN_VERSION_vector(0,11,0) -izipWith3 f as bs cs = phony $ \p -> +izipWith3 t f as bs cs = phonyvtype t $ \p -> let as' = G.stream (withW p as) bs' = G.stream (withW p bs) cs' = G.stream (withW p cs) sz = smallest [sSize as', sSize bs', sSize cs'] in proxyW (G.unstream $ Bundle.fromStream (Stream.zipWith3 (uncurry f) (Stream.indexed (sElems as')) (sElems bs') (sElems cs')) sz) p #else -izipWith3 f as bs cs = phony $ \p -> +izipWith3 t f as bs cs = phonyvtype t $ \p -> proxyW (G.unstream (Stream.zipWith3 (uncurry f) (Stream.indexed (G.stream (withW p as))) (G.stream (withW p bs)) (G.stream (withW p cs)))) p #endif -izipWith4 :: (SVECTOR tya a, SVECTOR tyb b, SVECTOR tyc c, SVECTOR tyd d, SVECTOR tye e) - => (Int -> a -> b -> c -> d -> e) - -> Vector tya a -> Vector tyb b -> Vector tyc c -> Vector tyd d -> Vector tye e +{-@ +assume izipWith4 + :: x:VSEXPTYPE s e + -> (Int -> a -> b -> c -> d -> e) + -> Vector a -> Vector b -> Vector c -> Vector d -> TVector e (vstypeOf x) +@-} +izipWith4 :: (Storable a, Storable b, Storable c, Storable d, Storable e) + => VSEXPTYPE s e + -> (Int -> a -> b -> c -> d -> e) + -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e {-# INLINE izipWith4 #-} #if MIN_VERSION_vector(0,11,0) -izipWith4 f as bs cs ds = phony $ \p -> +izipWith4 t f as bs cs ds = phonyvtype t $ \p -> let as' = G.stream (withW p as) bs' = G.stream (withW p bs) cs' = G.stream (withW p cs) @@ -1164,18 +1278,25 @@ izipWith4 f as bs cs ds = phony $ \p -> sz = smallest [ sSize as', sSize bs', sSize cs', sSize ds'] in proxyW (G.unstream $ Bundle.fromStream (Stream.zipWith4 (uncurry f) (Stream.indexed (sElems as')) (sElems bs') (sElems cs') (sElems ds')) sz) p #else -izipWith4 f as bs cs ds = phony $ \p -> +izipWith4 t f as bs cs ds = phonyvtype t $ \p -> proxyW (G.unstream (Stream.zipWith4 (uncurry f) (Stream.indexed (G.stream (withW p as))) (G.stream (withW p bs)) (G.stream (withW p cs)) (G.stream (withW p ds)))) p #endif -izipWith5 :: (SVECTOR tya a, SVECTOR tyb b, SVECTOR tyc c, SVECTOR tyd d, SVECTOR tye e, - SVECTOR tyf f) - => (Int -> a -> b -> c -> d -> e -> f) - -> Vector tya a -> Vector tyb b -> Vector tyc c -> Vector tyd d -> Vector tye e - -> Vector tyf f +{-@ +assume izipWith5 :: x:VSEXPTYPE s f + -> (Int -> a -> b -> c -> d -> e -> f) + -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e + -> TVector f (vstypeOf x) +@-} +izipWith5 :: (Storable a, Storable b, Storable c, Storable d, Storable e, + Storable f) + => VSEXPTYPE s f + -> (Int -> a -> b -> c -> d -> e -> f) + -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e + -> Vector f {-# INLINE izipWith5 #-} #if MIN_VERSION_vector(0,11,0) -izipWith5 f as bs cs ds es = phony $ \p -> +izipWith5 t f as bs cs ds es = phonyvtype t $ \p -> let as' = G.stream (withW p as) bs' = G.stream (withW p bs) cs' = G.stream (withW p cs) @@ -1184,18 +1305,25 @@ izipWith5 f as bs cs ds es = phony $ \p -> sz = smallest [ sSize as', sSize bs', sSize cs', sSize ds', sSize es'] in proxyW (G.unstream $ Bundle.fromStream (Stream.zipWith5 (uncurry f) (Stream.indexed (sElems as')) (sElems bs') (sElems cs') (sElems ds') (sElems es')) sz) p #else -izipWith5 f as bs cs ds es = phony $ \p -> +izipWith5 t f as bs cs ds es = phonyvtype t $ \p -> proxyW (G.unstream (Stream.zipWith5 (uncurry f) (Stream.indexed (G.stream (withW p as))) (G.stream (withW p bs)) (G.stream (withW p cs)) (G.stream (withW p ds)) (G.stream (withW p es)))) p #endif -izipWith6 :: (SVECTOR tya a, SVECTOR tyb b, SVECTOR tyc c, SVECTOR tyd d, SVECTOR tye e, - SVECTOR tyf f, SVECTOR tyg g) - => (Int -> a -> b -> c -> d -> e -> f -> g) - -> Vector tya a -> Vector tyb b -> Vector tyc c -> Vector tyd d -> Vector tye e - -> Vector tyf f -> Vector tyg g +{-@ +assume izipWith6 :: x:VSEXPTYPE s g + -> (Int -> a -> b -> c -> d -> e -> f -> g) + -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e + -> Vector f -> TVector g (vstypeOf x) +@-} +izipWith6 :: (Storable a, Storable b, Storable c, Storable d, Storable e, + Storable f, Storable g) + => VSEXPTYPE s g + -> (Int -> a -> b -> c -> d -> e -> f -> g) + -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e + -> Vector f -> Vector g {-# INLINE izipWith6 #-} #if MIN_VERSION_vector(0,11,0) -izipWith6 f as bs cs ds es fs = phony $ \p -> +izipWith6 t f as bs cs ds es fs = phonyvtype t $ \p -> let as' = G.stream (withW p as) bs' = G.stream (withW p bs) cs' = G.stream (withW p cs) @@ -1205,14 +1333,14 @@ izipWith6 f as bs cs ds es fs = phony $ \p -> sz = smallest [ sSize as', sSize bs', sSize cs', sSize ds', sSize es', sSize fs'] in proxyW (G.unstream $ Bundle.fromStream (Stream.zipWith6 (uncurry f) (Stream.indexed (sElems as')) (sElems bs') (sElems cs') (sElems ds') (sElems es') (sElems fs')) sz) p #else -izipWith6 f as bs cs ds es fs = phony $ \p -> +izipWith6 t f as bs cs ds es fs = phonyvtype t $ \p -> proxyW (G.unstream (Stream.zipWith6 (uncurry f) (Stream.indexed (G.stream (withW p as))) (G.stream (withW p bs)) (G.stream (withW p cs)) (G.stream (withW p ds)) (G.stream (withW p es)) (G.stream (withW p fs)))) p #endif -- Monadic zipping -- --------------- - +{- -- | /O(min(m,n))/ Zip the two vectors with the monadic action and yield a -- vector of results zipWithM :: (MonadR m, VECTOR (Region m) tya a, VECTOR (Region m) tyb b, VECTOR (Region m) tyc c, ElemRep V tya ~ a, ElemRep V tyb ~ b, ElemRep V tyc ~ c) @@ -1240,13 +1368,12 @@ zipWithM f xs ys = phony $ \p -> return $ G.unstream $ Stream.unsafeFromList (MStream.size s) zs #endif - -- | /O(min(m,n))/ Zip the two vectors with the monadic action and ignore the -- results -zipWithM_ :: (Monad m, SVECTOR tya a, SVECTOR tyb b) +zipWithM_ :: (Monad m, Storable a, Storable b) => (a -> b -> m c) - -> Vector tya a - -> Vector tyb b + -> Vector a + -> Vector b -> m () {-# INLINE zipWithM_ #-} #if MIN_VERSION_vector(0,11,0) @@ -1679,26 +1806,27 @@ scanr1' f v = phony $ unW . proxyFW (G.scanr1' f) v -- Conversions - Lists -- ------------------------ - +-} -- | /O(n)/ Convert a vector to a list -toList :: SVECTOR ty a => Vector ty a -> [a] +toList :: Storable a => Vector a -> [a] {-# INLINE toList #-} toList v = phony $ proxyFW G.toList v -- | /O(n)/ Convert a list to a vector -fromList :: forall ty a . SVECTOR ty a => [a] -> Vector ty a +{-@ assume fromList :: forall a . Storable a => t:VSEXPTYPE s a -> [a] -> TVector a (vstypeOf t) @-} +fromList :: Storable a => VSEXPTYPE s a -> [a] -> Vector a {-# INLINE fromList #-} -fromList xs = phony $ proxyW (G.fromListN (Prelude.length xs) xs) +fromList t xs = phonyvtype t $ proxyW (G.fromListN (Prelude.length xs) xs) -- | /O(n)/ Convert the first @n@ elements of a list to a vector -- -- @ -- fromListN n xs = 'fromList' ('take' n xs) -- @ -fromListN :: forall ty a . SVECTOR ty a => Int -> [a] -> Vector ty a +fromListN :: Storable a => VSEXPTYPE s a -> Int -> [a] -> Vector a {-# INLINE fromListN #-} -fromListN i l = phony $ proxyW (G.fromListN i l) - +fromListN t i l = phonyvtype t $ proxyW (G.fromListN i l) +{- -- Conversions - Unsafe casts -- -------------------------- @@ -1745,11 +1873,20 @@ copy :: (MonadR m, VECTOR (Region m) ty a, ElemRep V ty ~ a) => MVector (Region m) ty a -> Vector ty a -> m () {-# INLINE copy #-} copy m1 v2 = withAcquire $ \p -> G.copy (Mutable.withW p m1) (withW p v2) + -} + +phony + :: forall s r. + (forall t. Reifies t (AcquireIO s, IO R.SEXPTYPE) => Proxy t -> r) -> r +phony f = + reify acquireIO $ \p -> f p + where + acquireIO = violation "phony" "phony acquire or SEXPTYPE called." -phony :: (forall t . Reifies t (AcquireIO s) => Proxy t -> r) -> r -phony f = reify (AcquireIO acquireIO) $ \p -> f p +phonyvtype + :: VSEXPTYPE s a -> + (forall t. Reifies t (AcquireIO s, IO R.SEXPTYPE) => Proxy t -> r) -> r +phonyvtype t f = + reify (acquireIO, return (vstypeOf t)) $ \p -> f p where - acquireIO :: SEXP V ty -> IO (SEXP g ty) - acquireIO x = mask_ $ do - R.preserveObject x - return $ R.unsafeRelease x + acquireIO = violation "phony" "phony acquire called." diff --git a/inline-r/src/Data/Vector/SEXP/Base.hs b/inline-r/src/Data/Vector/SEXP/Base.hs index b0502f80..28a608c0 100644 --- a/inline-r/src/Data/Vector/SEXP/Base.hs +++ b/inline-r/src/Data/Vector/SEXP/Base.hs @@ -5,7 +5,9 @@ {-# OPTIONS_GHC -fplugin-opt=LiquidHaskell:--skip-module=False #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} +{-# LANGUAGE GADTs #-} {-# LANGUAGE TypeFamilies #-} +{-@ LIQUID "--exact-data-cons" @-} module Data.Vector.SEXP.Base where @@ -36,6 +38,30 @@ type family ElemRep s (a :: SEXPTYPE) where ElemRep s 'Expr = SEXP s ElemRep s 'Raw = Word8 +data VSEXPTYPE s a where + VChar :: VSEXPTYPE s Word8 + VLogical :: VSEXPTYPE s Logical + VInt :: VSEXPTYPE s Int32 + VReal :: VSEXPTYPE s Double + VComplex :: VSEXPTYPE s (Complex Double) + VString :: VSEXPTYPE s (SEXP s) + VVector :: VSEXPTYPE s (SEXP s) + VExpr :: VSEXPTYPE s (SEXP s) + VRaw :: VSEXPTYPE s Word8 + + +{-@ reflect vstypeOf @-} +vstypeOf :: VSEXPTYPE s a -> SEXPTYPE +vstypeOf VChar = Char +vstypeOf VLogical = Logical +vstypeOf VInt = Int +vstypeOf VReal = Real +vstypeOf VComplex = Complex +vstypeOf VString = String +vstypeOf VVector = Vector +vstypeOf VExpr = Expr +vstypeOf VRaw = Raw + -- | 'ElemRep' in the form of a relation, for convenience. type E s a b = ElemRep s a ~ b @@ -43,4 +69,4 @@ type E s a b = ElemRep s a ~ b -- type VECTOR s ty a = (Storable a, IsVector ty, SingI ty) -- | Constraint synonym for all operations on vectors. -type SVECTOR ty a = (Storable a, IsVector ty, SingI ty, ElemRep V ty ~ a) +-- type SVECTOR ty a = (Storable a, IsVector ty, SingI ty, ElemRep V ty ~ a)