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..20b100c9 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
+{-@ 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 = phony $ 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 = phony $ 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 = phony $ 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
+{-@ 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 = phony $ 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 = phony $ 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 = phony $ 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 = phony $ 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) -> Vector 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 = phony $ 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) -> Vector 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 = phony $ proxyW (G.constructrN n (g.unW))
-- Enumeration
-- -----------
@@ -736,83 +780,95 @@ 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
+{-@ 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 = phony $ 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
+{-@ enumFromStepN :: x:VSEXPTYPE 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 _t f t s = phony $ 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
+{-@ enumFromTo :: x:VSEXPTYPE s a -> a -> a -> Vector 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 _t f t = phony $ 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
+{-@ 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 _t f t s = phony $ proxyW (G.enumFromThenTo f t s)
-- Concatenation
-- -------------
-- | /O(n)/ Prepend an element
-cons :: SVECTOR ty a => a -> Vector ty a -> Vector ty a
+{-@ cons :: a -> v:Vector a -> TVector a (Data.Vector.SEXP.vtypeOf x) @-}
+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
+{-@ snoc :: v:Vector a -> a -> TVector a (Data.Vector.SEXP.vtypeOf x) @-}
+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
+{-@ 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 = phony $ \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)
+{-@ 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 = phony $ \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)
+{-@ 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 = phony $ \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
+{-@ 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 = phony $ \p -> unW $ G.create (Mutable.withW p <$> f)
+{-
-- Restricting memory usage
-- ------------------------
@@ -1679,26 +1735,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 = phony $ 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 = phony $ proxyW (G.fromListN i l)
+{-
-- Conversions - Unsafe casts
-- --------------------------
@@ -1745,11 +1802,12 @@ 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 t . Reifies t (AcquireIO s) => Proxy t -> r) -> r
-phony f = reify (AcquireIO acquireIO) $ \p -> f p
+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 :: SEXP V ty -> IO (SEXP g ty)
- acquireIO x = mask_ $ do
- R.preserveObject x
- return $ R.unsafeRelease x
+ acquireIO = violation "phony" "phony acquire or SEXPTYPE 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)