packages feed

comfort-array 0.3.1 → 0.4

raw patch · 14 files changed

+721/−54 lines, 14 filesdep +ChasingBottomsdep +prelude-compatdep +semigroupsdep ~non-emptyPVP ok

version bump matches the API change (PVP)

Dependencies added: ChasingBottoms, prelude-compat, semigroups, tagged

Dependency ranges changed: non-empty

API changes (from Hackage documentation)

- Data.Array.Comfort.Shape: data DeferredIndex ix
- Data.Array.Comfort.Shape: instance (GHC.Classes.Eq part, GHC.Classes.Eq size) => GHC.Classes.Eq (Data.Array.Comfort.Shape.Triangular part size)
- Data.Array.Comfort.Shape: instance Foreign.Storable.Storable (Data.Array.Comfort.Shape.DeferredIndex ix)
- Data.Array.Comfort.Shape: instance GHC.Classes.Eq (Data.Array.Comfort.Shape.DeferredIndex ix)
- Data.Array.Comfort.Shape: instance GHC.Show.Show (Data.Array.Comfort.Shape.DeferredIndex ix)
+ Data.Array.Comfort.Boxed: fromContainer :: C f => f a -> Array (Shape f) a
+ Data.Array.Comfort.Boxed: mapShape :: (C sh0, C sh1) => (sh0 -> sh1) -> Array sh0 a -> Array sh1 a
+ Data.Array.Comfort.Boxed: replicate :: C sh => sh -> a -> Array sh a
+ Data.Array.Comfort.Boxed: reshape :: (C sh0, C sh1) => sh1 -> Array sh0 a -> Array sh1 a
+ Data.Array.Comfort.Boxed: toContainer :: C f => Array (Shape f) a -> f a
+ Data.Array.Comfort.Boxed: toMap :: Ord k => Array (Set k) a -> Map k a
+ Data.Array.Comfort.Container: class (Foldable f) => C f where {
+ Data.Array.Comfort.Container: class (C f) => EqShape f
+ Data.Array.Comfort.Container: class (C f) => NFShape f
+ Data.Array.Comfort.Container: data family Shape f;
+ Data.Array.Comfort.Container: eqShape :: EqShape f => Shape f -> Shape f -> Bool
+ Data.Array.Comfort.Container: fromList :: C f => Shape f -> [a] -> f a
+ Data.Array.Comfort.Container: instance (Control.DeepSeq.NFData k, GHC.Classes.Ord k) => Data.Array.Comfort.Container.NFShape (Data.Map.Internal.Map k)
+ Data.Array.Comfort.Container: instance (Control.DeepSeq.NFData k, GHC.Classes.Ord k) => Data.Array.Comfort.Container.NFShape (Data.NonEmpty.Map.T k)
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.C Data.Empty.T
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.C []
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.C f => Data.Array.Comfort.Container.C (Data.NonEmptyPrivate.T f)
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.C f => Data.Array.Comfort.Shape.C (Data.Array.Comfort.Container.Shape f)
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.EqShape Data.Empty.T
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.EqShape []
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.EqShape f => Data.Array.Comfort.Container.EqShape (Data.NonEmptyPrivate.T f)
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.EqShape f => GHC.Classes.Eq (Data.Array.Comfort.Container.Shape f)
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.NFShape Data.Empty.T
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.NFShape []
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.NFShape f => Control.DeepSeq.NFData (Data.Array.Comfort.Container.Shape f)
+ Data.Array.Comfort.Container: instance Data.Array.Comfort.Container.NFShape f => Data.Array.Comfort.Container.NFShape (Data.NonEmptyPrivate.T f)
+ Data.Array.Comfort.Container: instance GHC.Classes.Ord k => Data.Array.Comfort.Container.C (Data.Map.Internal.Map k)
+ Data.Array.Comfort.Container: instance GHC.Classes.Ord k => Data.Array.Comfort.Container.C (Data.NonEmpty.Map.T k)
+ Data.Array.Comfort.Container: instance GHC.Classes.Ord k => Data.Array.Comfort.Container.EqShape (Data.Map.Internal.Map k)
+ Data.Array.Comfort.Container: instance GHC.Classes.Ord k => Data.Array.Comfort.Container.EqShape (Data.NonEmpty.Map.T k)
+ Data.Array.Comfort.Container: instance GHC.Show.Show (Data.Array.Comfort.Container.Shape Data.Empty.T)
+ Data.Array.Comfort.Container: instance GHC.Show.Show (Data.Array.Comfort.Container.Shape [])
+ Data.Array.Comfort.Container: instance GHC.Show.Show k => GHC.Show.Show (Data.Array.Comfort.Container.Shape (Data.Map.Internal.Map k))
+ Data.Array.Comfort.Container: instance GHC.Show.Show k => GHC.Show.Show (Data.Array.Comfort.Container.Shape (Data.NonEmpty.Map.T k))
+ Data.Array.Comfort.Container: rnfShape :: NFShape f => Shape f -> ()
+ Data.Array.Comfort.Container: shapeSize :: C f => Shape f -> Int
+ Data.Array.Comfort.Container: toShape :: C f => f a -> Shape f
+ Data.Array.Comfort.Container: }
+ Data.Array.Comfort.Shape: DeferredIndex :: Int -> DeferredIndex sh
+ Data.Array.Comfort.Shape: Zero :: Zero
+ Data.Array.Comfort.Shape: class (C sh, Eq sh) => Static sh
+ Data.Array.Comfort.Shape: data Zero
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.Static sh0, Data.Array.Comfort.Shape.Static sh1) => Data.Array.Comfort.Shape.Static (sh0 Data.Array.Comfort.Shape.:+: sh1)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.Static sh0, Data.Array.Comfort.Shape.Static sh1) => Data.Array.Comfort.Shape.Static (sh0, sh1)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.Static sh0, Data.Array.Comfort.Shape.Static sh1, Data.Array.Comfort.Shape.Static sh2) => Data.Array.Comfort.Shape.Static (sh0, sh1, sh2)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.TriangularPart part, Data.Array.Comfort.Shape.Static size) => Data.Array.Comfort.Shape.Static (Data.Array.Comfort.Shape.Triangular part size)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.TriangularPart part, GHC.Classes.Eq size) => GHC.Classes.Eq (Data.Array.Comfort.Shape.Triangular part size)
+ Data.Array.Comfort.Shape: instance (GHC.Enum.Enum n, GHC.Enum.Bounded n) => Data.Array.Comfort.Shape.Static (Data.Array.Comfort.Shape.Enumeration n)
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.C Data.Array.Comfort.Shape.Zero
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.C sh => Data.Array.Comfort.Shape.C (Data.Tagged.Tagged s sh)
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.Indexed sh => Data.Array.Comfort.Shape.Indexed (Data.Tagged.Tagged s sh)
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.InvIndexed sh => Data.Array.Comfort.Shape.InvIndexed (Data.Tagged.Tagged s sh)
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.Static ()
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.Static Data.Array.Comfort.Shape.Zero
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.Static sh => Data.Array.Comfort.Shape.Static (Data.Array.Comfort.Shape.Deferred sh)
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.Static sh => Data.Array.Comfort.Shape.Static (Data.Tagged.Tagged s sh)
+ Data.Array.Comfort.Shape: instance Foreign.Storable.Storable (Data.Array.Comfort.Shape.DeferredIndex sh)
+ Data.Array.Comfort.Shape: instance GHC.Classes.Eq (Data.Array.Comfort.Shape.DeferredIndex sh)
+ Data.Array.Comfort.Shape: instance GHC.Classes.Eq Data.Array.Comfort.Shape.Zero
+ Data.Array.Comfort.Shape: instance GHC.Classes.Ord (Data.Array.Comfort.Shape.DeferredIndex sh)
+ Data.Array.Comfort.Shape: instance GHC.Classes.Ord Data.Array.Comfort.Shape.Zero
+ Data.Array.Comfort.Shape: instance GHC.Show.Show (Data.Array.Comfort.Shape.DeferredIndex sh)
+ Data.Array.Comfort.Shape: instance GHC.Show.Show Data.Array.Comfort.Shape.Zero
+ Data.Array.Comfort.Shape: newtype DeferredIndex sh
+ Data.Array.Comfort.Shape: static :: Static sh => sh
+ Data.Array.Comfort.Shape: zeroBasedSplit :: Real n => n -> ZeroBased n -> ZeroBased n :+: ZeroBased n
+ Data.Array.Comfort.Storable: append :: (C shx, C shy, Storable a) => Array shx a -> Array shy a -> Array (shx :+: shy) a
+ Data.Array.Comfort.Storable: argMaximum :: (InvIndexed sh, Index sh ~ ix, Storable a, Ord a) => Array sh a -> (ix, a)
+ Data.Array.Comfort.Storable: argMinimum :: (InvIndexed sh, Index sh ~ ix, Storable a, Ord a) => Array sh a -> (ix, a)
+ Data.Array.Comfort.Storable: drop :: (Integral n, Storable a) => n -> Array (ZeroBased n) a -> Array (ZeroBased n) a
+ Data.Array.Comfort.Storable: foldMap :: (C sh, Storable a, Ord a, Semigroup m) => (a -> m) -> Array sh a -> m
+ Data.Array.Comfort.Storable: foldl :: (C sh, Storable a) => (b -> a -> b) -> b -> Array sh a -> b
+ Data.Array.Comfort.Storable: foldl1 :: (C sh, Storable a) => (a -> a -> a) -> Array sh a -> a
+ Data.Array.Comfort.Storable: fromContainer :: (C f, Storable a) => f a -> Array (Shape f) a
+ Data.Array.Comfort.Storable: limits :: (C sh, Storable a, Ord a) => Array sh a -> (a, a)
+ Data.Array.Comfort.Storable: maximum :: (C sh, Storable a, Ord a) => Array sh a -> a
+ Data.Array.Comfort.Storable: minimum :: (C sh, Storable a, Ord a) => Array sh a -> a
+ Data.Array.Comfort.Storable: product :: (C sh, Storable a, Num a) => Array sh a -> a
+ Data.Array.Comfort.Storable: singleton :: Storable a => a -> Array () a
+ Data.Array.Comfort.Storable: split :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> (Array sh0 a, Array sh1 a)
+ Data.Array.Comfort.Storable: sum :: (C sh, Storable a, Num a) => Array sh a -> a
+ Data.Array.Comfort.Storable: take :: (Integral n, Storable a) => n -> Array (ZeroBased n) a -> Array (ZeroBased n) a
+ Data.Array.Comfort.Storable: takeLeft :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> Array sh0 a
+ Data.Array.Comfort.Storable: takeRight :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> Array sh1 a
+ Data.Array.Comfort.Storable: toAssociations :: (Indexed sh, Storable a) => Array sh a -> [(Index sh, a)]
+ Data.Array.Comfort.Storable: toContainer :: (C f, Storable a) => Array (Shape f) a -> f a
+ Data.Array.Comfort.Storable: zipWith :: (C sh, Eq sh, Storable a, Storable b, Storable c) => (a -> b -> c) -> Array sh a -> Array sh b -> Array sh c
+ Data.Array.Comfort.Storable.Private: instance (Data.Array.Comfort.Shape.C sh, GHC.Classes.Eq sh, Foreign.Storable.Storable a, GHC.Classes.Eq a) => GHC.Classes.Eq (Data.Array.Comfort.Storable.Private.Array sh a)
+ Data.Array.Comfort.Storable.Unchecked: append :: (C shx, C shy, Storable a) => Array shx a -> Array shy a -> Array (shx :+: shy) a
+ Data.Array.Comfort.Storable.Unchecked: drop :: (Integral n, Storable a) => n -> Array (ZeroBased n) a -> Array (ZeroBased n) a
+ Data.Array.Comfort.Storable.Unchecked: foldl :: (C sh, Storable a) => (b -> a -> b) -> b -> Array sh a -> b
+ Data.Array.Comfort.Storable.Unchecked: product :: (C sh, Storable a, Num a) => Array sh a -> a
+ Data.Array.Comfort.Storable.Unchecked: singleton :: Storable a => a -> Array () a
+ Data.Array.Comfort.Storable.Unchecked: split :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> (Array sh0 a, Array sh1 a)
+ Data.Array.Comfort.Storable.Unchecked: sum :: (C sh, Storable a, Num a) => Array sh a -> a
+ Data.Array.Comfort.Storable.Unchecked: take :: (Integral n, Storable a) => n -> Array (ZeroBased n) a -> Array (ZeroBased n) a
+ Data.Array.Comfort.Storable.Unchecked: takeLeft :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> Array sh0 a
+ Data.Array.Comfort.Storable.Unchecked: takeRight :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> Array sh1 a
+ Data.Array.Comfort.Storable.Unchecked: zipWith :: (C sh, Storable a, Storable b, Storable c) => (a -> b -> c) -> Array sh a -> Array sh b -> Array sh c
- Data.Array.Comfort.Boxed: fromAssociations :: Indexed sh => sh -> a -> [(Index sh, a)] -> Array sh a
+ Data.Array.Comfort.Boxed: fromAssociations :: Indexed sh => a -> sh -> [(Index sh, a)] -> Array sh a
- Data.Array.Comfort.Shape: deferIndex :: (Indexed sh, Index sh ~ ix) => sh -> ix -> DeferredIndex ix
+ Data.Array.Comfort.Shape: deferIndex :: (Indexed sh, Index sh ~ ix) => sh -> ix -> DeferredIndex sh
- Data.Array.Comfort.Shape: revealIndex :: (InvIndexed sh, Index sh ~ ix) => sh -> DeferredIndex ix -> ix
+ Data.Array.Comfort.Shape: revealIndex :: (InvIndexed sh, Index sh ~ ix) => sh -> DeferredIndex sh -> ix
- Data.Array.Comfort.Storable: fromAssociations :: (Indexed sh, Storable a) => sh -> a -> [(Index sh, a)] -> Array sh a
+ Data.Array.Comfort.Storable: fromAssociations :: (Indexed sh, Storable a) => a -> sh -> [(Index sh, a)] -> Array sh a
- Data.Array.Comfort.Storable.Private: fromAssociations :: (Indexed sh, Storable a) => sh -> a -> [(Index sh, a)] -> Array sh a
+ Data.Array.Comfort.Storable.Private: fromAssociations :: (Indexed sh, Storable a) => a -> sh -> [(Index sh, a)] -> Array sh a
- Data.Array.Comfort.Storable.Unchecked: fromAssociations :: (Indexed sh, Storable a) => sh -> a -> [(Index sh, a)] -> Array sh a
+ Data.Array.Comfort.Storable.Unchecked: fromAssociations :: (Indexed sh, Storable a) => a -> sh -> [(Index sh, a)] -> Array sh a

Files

Changes.md view
@@ -1,5 +1,13 @@ # Change log for the `comfort-array` package +## 0.4++ * `fromAssocations`: Make default value the first parameter.+   It is most oftenly zero and thus less variable than the array size.++ * `Shape.DeferredIndex`:+   Now uses the shape as the type parameter, not the index type.+ ## 0.3   * `Storable.Mutable.Array`: Replace `ForeignPtr` by `Array.Guarded.MutablePtr`.
comfort-array.cabal view
@@ -1,5 +1,5 @@ Name:             comfort-array-Version:          0.3.1+Version:          0.4 License:          BSD3 License-File:     LICENSE Author:           Henning Thielemann <haskell@henning-thielemann.de>@@ -36,16 +36,24 @@   * @ZeroBased, OneBased@:     Arrays with fixed lower bound, either 0 or 1, respectively.   .+  * @Zero, ()@:+    Arrays with fixed size 0 or 1, respectively.+  .+  * @Enumeration@:+    Arrays with indices like 'LT', 'EQ', 'GT' and a shape of fixed size.+  .   * @(:+:)@:     The Append type constructor allows to respresent block arrays,     e.g. block matrices.-  .-  * @Enumeration@: Arrays with indices like 'LT', 'EQ', 'GT' and dummy shape.+    It also allows to represent non-empty arrays via @():+:sh@.   .   * @Set@: Use an arbitrary ordered set as index set.   .-  * @Triangular@: A 2D array with the shape of lower or upper triangular matrix.+  * @Triangular@:+    A 2D array with the shape of a lower or upper triangular matrix.   .+  * @Tagged@: Statically distinguish shapes and indices that are isomorphic.+  .   The @lapack@ package defines even more fancy shapes   like tall rectangular matrices, triangular matrices and banded matrices. @@ -56,7 +64,7 @@   Changes.md  Source-Repository this-  Tag:         0.3.1+  Tag:         0.4   Type:        darcs   Location:    http://hub.darcs.net/thielema/comfort-array/ @@ -70,15 +78,18 @@  Library   Build-Depends:-    primitive >=0.6.4 && <0.7,+    primitive >=0.6.4 && <0.8,     guarded-allocation >=0.0.1 && <0.1,     storable-record >=0.0.1 && <0.1,+    tagged >=0.7 && <0.9,     deepseq >=1.3 && <1.5,     QuickCheck >=2 && <3,+    semigroups >=0.18.3 && <1.0,     containers >=0.4 && <0.7,     transformers >=0.3 && <0.6,-    non-empty >=0.3 && <0.4,+    non-empty >=0.3.2 && <0.4,     utility-ht >=0.0.10 && <0.1,+    prelude-compat >=0.0 && <0.1,     base >=4.5 && <5    If flag(setIndex)@@ -101,15 +112,20 @@     Data.Array.Comfort.Storable.Mutable.Unchecked     Data.Array.Comfort.Storable.Mutable.Private     Data.Array.Comfort.Boxed+    Data.Array.Comfort.Container   Other-Modules:     Data.Array.Comfort.Shape.Set     Data.Array.Comfort.Shape.Utility     Data.Array.Comfort.Boxed.Unchecked+    Data.Array.Comfort.Storable.Memory+    Data.Array.Comfort.Check  Test-Suite comfort-array-test   Type: exitcode-stdio-1.0   Build-Depends:     comfort-array,+    ChasingBottoms >=1.2.2 && <1.4,+    tagged,     containers,     QuickCheck,     base@@ -119,5 +135,6 @@   Hs-Source-Dirs:   test   Main-Is:          Main.hs   Other-Modules:+    Test.Storable     Test.Shape     Test.Utility
src/Data/Array/Comfort/Boxed.hs view
@@ -1,13 +1,19 @@ module Data.Array.Comfort.Boxed (    Array,    shape,+   reshape,+   mapShape,    (!),    Array.toList,-   toAssociations,    Array.fromList,-   fromMap,    Array.vectorFromList,+   toAssociations,+   fromMap,+   toMap,+   fromContainer,+   toContainer,    indices,+   Array.replicate,     Array.map,    zipWith,@@ -17,6 +23,8 @@    ) where  import qualified Data.Array.Comfort.Boxed.Unchecked as Array+import qualified Data.Array.Comfort.Container as Container+import qualified Data.Array.Comfort.Check as Check import qualified Data.Array.Comfort.Shape as Shape import Data.Array.Comfort.Boxed.Unchecked (Array(Array)) @@ -26,25 +34,43 @@ import Control.Monad.ST (runST) import Control.Applicative ((<$>)) +import qualified Data.Foldable as Fold import qualified Data.Map as Map+import qualified Data.Set as Set import Data.Map (Map) import Data.Set (Set) import Data.Foldable (forM_) -import Prelude hiding (zipWith)+import Prelude hiding (zipWith, replicate)   shape :: Array.Array sh a -> sh shape = Array.shape +reshape :: (Shape.C sh0, Shape.C sh1) => sh1 -> Array sh0 a -> Array sh1 a+reshape = Check.reshape "Boxed" shape Array.reshape +mapShape ::+   (Shape.C sh0, Shape.C sh1) => (sh0 -> sh1) -> Array sh0 a -> Array sh1 a+mapShape f arr = reshape (f $ shape arr) arr++ indices :: (Shape.Indexed sh) => sh -> Array.Array sh (Shape.Index sh) indices sh = Array.fromList sh $ Shape.indices sh  fromMap :: (Ord k) => Map k a -> Array (Set k) a fromMap m = Array.fromList (Map.keysSet m) (Map.elems m) +toMap :: (Ord k) => Array (Set k) a -> Map k a+toMap arr = Map.fromAscList $ zip (Set.toAscList $ shape arr) (Array.toList arr) +fromContainer :: (Container.C f) => f a -> Array (Container.Shape f) a+fromContainer xs = Array.fromList (Container.toShape xs) (Fold.toList xs)++toContainer :: (Container.C f) => Array (Container.Shape f) a -> f a+toContainer arr = Container.fromList (Array.shape arr) (Array.toList arr)++ infixl 9 !  (!) :: (Shape.Indexed sh) => Array sh a -> Shape.Index sh -> a@@ -87,8 +113,8 @@ toAssociations arr = zip (Shape.indices $ shape arr) (Array.toList arr)  fromAssociations ::-   (Shape.Indexed sh) => sh -> a -> [(Shape.Index sh, a)] -> Array sh a-fromAssociations sh a xs = runST (do+   (Shape.Indexed sh) => a -> sh -> [(Shape.Index sh, a)] -> Array sh a+fromAssociations a sh xs = runST (do    marr <- Prim.newArray (Shape.size sh) a    forM_ xs $ \(ix,x) -> Prim.writeArray marr (Shape.offset sh ix) x    Array sh <$> Prim.unsafeFreezeArray marr)
src/Data/Array/Comfort/Boxed/Unchecked.hs view
@@ -8,13 +8,13 @@ import qualified Control.Monad.Trans.Class as MT import qualified Control.Monad.Trans.State as MS import Control.Monad (liftM)-import Control.Applicative ((<$>))+import Control.Applicative (Applicative, pure, (<*>), (<$>)) import Control.DeepSeq (NFData, rnf)  import qualified Data.Traversable as Trav import qualified Data.Foldable as Fold import qualified Data.List as List-import Prelude hiding (map, )+import Prelude hiding (map, zipWith, replicate)   data Array sh a =@@ -24,9 +24,12 @@    }  instance (Shape.C sh, Show sh, Show a) => Show (Array sh a) where-   show arr =-      "BoxedArray.fromList " ++-      showsPrec 11 (shape arr) (' ' : show (toListLazy arr))+   showsPrec p arr =+      showParen (p>10) $+         showString "BoxedArray.fromList " .+         showsPrec 11 (shape arr) .+         showChar ' ' .+         shows (toListLazy arr)   instance (Shape.C sh, NFData sh, NFData a) => NFData (Array sh a) where@@ -35,6 +38,14 @@ instance (Shape.C sh) => Functor (Array sh) where    fmap = map +{- |+We must restrict 'Applicative' to 'Shape.Static' because of 'pure'.+Because the shape is static, we do not need a size check in '(<*>)'.+-}+instance (Shape.Static sh) => Applicative (Array sh) where+   pure = replicate Shape.static+   (<*>) = zipWith ($)+ instance (Shape.C sh) => Fold.Foldable (Array sh) where    fold = Fold.fold . buffer    foldMap f = Fold.foldMap f . buffer@@ -78,6 +89,11 @@ vectorFromList xs =    let arr = Prim.fromList xs    in Array (Shape.ZeroBased $ Prim.sizeofArray arr) arr++replicate :: (Shape.C sh) => sh -> a -> Array sh a+replicate sh a =+   Array sh $+   STStrict.runST (Prim.unsafeFreezeArray  =<< Prim.newArray (Shape.size sh) a)  map :: (Shape.C sh) => (a -> b) -> Array sh a -> Array sh b map f (Array sh arr) = Array sh $ Prim.mapArray' f arr
+ src/Data/Array/Comfort/Check.hs view
@@ -0,0 +1,24 @@+module Data.Array.Comfort.Check where++import qualified Data.Array.Comfort.Shape as Shape++import Text.Printf (printf)+++{-# INLINE reshape #-}+reshape ::+   (Shape.C sh0, Shape.C sh1) =>+   String ->+   (array0 -> sh0) ->+   (sh1 -> array0 -> array1) ->+   sh1 -> array0 -> array1+reshape name shape uncheckedReshape sh1 arr =+   let n0 = Shape.size $ shape arr+       n1 = Shape.size sh1+   in if n0 == n1+         then uncheckedReshape sh1 arr+         else error $+              printf+                 ("Array.Comfort.%s.reshape: " +++                  "different sizes of old (%d) and new (%d) shape")+                 name n0 n1
+ src/Data/Array/Comfort/Container.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE TypeFamilies #-}+{- |+This module provides an array shape type,+that allows to store elements from a container+while preserving the container structure.+-}+module Data.Array.Comfort.Container (+   C(..), EqShape(..), NFShape(..),+   ) where++import qualified Data.Array.Comfort.Shape as Shape++import Control.DeepSeq (NFData, rnf)++import qualified Data.NonEmpty.Map as NonEmptyMap+import qualified Data.NonEmpty.Set as NonEmptySet+import qualified Data.NonEmpty.Class as NonEmptyC+import qualified Data.NonEmpty as NonEmpty+import qualified Data.Empty as Empty+import qualified Data.Map as Map+import qualified Data.Set as Set+-- import qualified Data.Complex as Complex+import Data.Map (Map)+import Data.Set (Set)+import Data.Foldable (Foldable)+import Data.Maybe (fromMaybe)+-- import Data.Complex (Complex((:+)))++++class (Foldable f) => C f where+   data Shape f+   shapeSize :: Shape f -> Int+   fromList :: Shape f -> [a] -> f a+   toShape :: f a -> Shape f++class (C f) => NFShape f where+   rnfShape :: Shape f -> ()++class (C f) => EqShape f where+   eqShape :: Shape f -> Shape f -> Bool+++instance (NFShape f) => NFData (Shape f) where+   rnf = rnfShape++instance (EqShape f) => Eq (Shape f) where+   (==) = eqShape++instance (C f) => Shape.C (Shape f) where+   size = shapeSize+   uncheckedSize = shapeSize+++instance C [] where+   data Shape [] = ShapeList Int+      deriving (Show)+   shapeSize (ShapeList n) = n+   toShape = ShapeList . length+   fromList _ = id++instance EqShape [] where+   eqShape (ShapeList n)  (ShapeList m) = n==m++instance NFShape [] where+   rnfShape (ShapeList n) = rnf n+++{-+instance Foldable only available since GHC-8.0. :-(+Could be circumvented by Data.Orphans+but that one also pulls in lots of dangerous instances.++instance C Complex where+   data Shape Complex = ShapeComplex+   shapeSize ShapeComplex = 2+   toShape (_:+_) = ShapeComplex+   fromList ShapeComplex xs =+      case xs of+         [r,i] -> r Complex.:+ i+         _ -> error "ShapeComplex: not two elements"++instance EqShape Complex where+   eqShape ShapeComplex ShapeComplex = True++instance NFShape Complex where+   rnfShape ShapeComplex = ()+-}+++instance (C f) => C (NonEmpty.T f) where+   data Shape (NonEmpty.T f) = ShapeNonEmpty (Shape f)+   shapeSize (ShapeNonEmpty c) = 1 + shapeSize c+   toShape = ShapeNonEmpty . toShape . NonEmpty.tail+   fromList (ShapeNonEmpty c) xt =+      case xt of+         [] -> error "ShapeNonEmpty: empty list"+         x:xs -> NonEmpty.cons x $ fromList c xs++instance (EqShape f) => EqShape (NonEmpty.T f) where+   eqShape (ShapeNonEmpty a) (ShapeNonEmpty b) = a==b++instance (NFShape f) => NFShape (NonEmpty.T f) where+   rnfShape (ShapeNonEmpty c) = rnfShape c+++instance C Empty.T where+   data Shape Empty.T = ShapeEmpty+      deriving (Show)+   shapeSize ShapeEmpty = 0+   toShape Empty.Cons = ShapeEmpty+   fromList ShapeEmpty xs =+      case xs of+         [] -> Empty.Cons+         _ -> error "ShapeEmpty: not empty"++instance EqShape Empty.T where+   eqShape ShapeEmpty ShapeEmpty = True++instance NFShape Empty.T where+   rnfShape ShapeEmpty = ()+++instance (Ord k) => C (Map k) where+   data Shape (Map k) = ShapeMap (Set k)+      deriving (Show)+   shapeSize (ShapeMap set) = Set.size set+   toShape = ShapeMap . Map.keysSet+   fromList (ShapeMap set) = Map.fromAscList . zip (Set.toAscList set)++instance (Ord k) => EqShape (Map k) where+   eqShape (ShapeMap set0) (ShapeMap set1) = set0==set1++instance (NFData k, Ord k) => NFShape (Map k) where+   rnfShape (ShapeMap set) = rnf set+++instance (Ord k) => C (NonEmptyMap.T k) where+   data Shape (NonEmptyMap.T k) = ShapeNonEmptyMap (NonEmptySet.T k)+      deriving (Show)+   shapeSize (ShapeNonEmptyMap set) = NonEmptySet.size set+   toShape = ShapeNonEmptyMap . NonEmptyMap.keysSet+   fromList (ShapeNonEmptyMap set) =+      NonEmptyMap.fromAscList . NonEmptyC.zip (NonEmptySet.toAscList set) .+      fromMaybe (error "ShapeNonEmptyMap: empty list") . NonEmpty.fetch++instance (Ord k) => EqShape (NonEmptyMap.T k) where+   eqShape (ShapeNonEmptyMap set0) (ShapeNonEmptyMap set1) = set0==set1++instance (NFData k, Ord k) => NFShape (NonEmptyMap.T k) where+   rnfShape (ShapeNonEmptyMap set) = rnf set
src/Data/Array/Comfort/Shape.hs view
@@ -4,14 +4,16 @@    C(..),    Indexed(..),    InvIndexed(..),+   Static(..), -   ZeroBased(..),+   Zero(Zero),+   ZeroBased(..), zeroBasedSplit,    OneBased(..),     Range(..),    Shifted(..),    Enumeration(..),-   Deferred(..), DeferredIndex, deferIndex, revealIndex,+   Deferred(..), DeferredIndex(..), deferIndex, revealIndex,     (:+:)(..), @@ -40,9 +42,13 @@  import qualified Data.Set as Set import qualified Data.NonEmpty as NonEmpty+import Data.Functor.Identity (Identity(Identity), runIdentity)+import Data.Function.HT (compose2)+import Data.Tagged (Tagged(Tagged, unTagged)) import Data.Set (Set) import Data.List.HT (tails) import Data.Tuple.HT (mapSnd, mapPair, swap, fst3, snd3, thd3)+import Data.Eq.HT (equating)   class C sh where@@ -80,7 +86,21 @@    uncheckedIndexFromOffset :: sh -> Int -> Index sh    uncheckedIndexFromOffset = indexFromOffset +class (C sh, Eq sh) => Static sh where+   static :: sh ++data Zero = Zero+   deriving (Eq, Ord, Show)++instance C Zero where+   size Zero = 0+   uncheckedSize Zero = 0++instance Static Zero where+   static = Zero++ instance C () where    size () = 1    uncheckedSize () = 1@@ -97,7 +117,10 @@    indexFromOffset () k = errorIndexFromOffset "()" k    uncheckedIndexFromOffset () _ = () +instance Static () where+   static = () + {- | 'ZeroBased' denotes a range starting at zero and has a certain length. -}@@ -139,7 +162,13 @@             else errorIndexFromOffset "ZeroBased" k0    uncheckedIndexFromOffset _ k = fromIntegral k +zeroBasedSplit :: (Real n) => n -> ZeroBased n -> ZeroBased n :+: ZeroBased n+zeroBasedSplit n (ZeroBased m) =+   if n<0+      then error "Shape.zeroBasedSplit: negative number of elements"+      else let k = min n m in ZeroBased k :+: ZeroBased (m-k) + {- | 'OneBased' denotes a range starting at one and has a certain length. -}@@ -334,6 +363,9 @@ intFromEnum :: (Enum n) => Enumeration n -> n -> Int intFromEnum Enumeration = fromEnum +instance (Enum n, Bounded n) => Static (Enumeration n) where+   static = Enumeration+ instance Storable (Enumeration n) where    {-# INLINE sizeOf #-}    {-# INLINE alignment #-}@@ -373,12 +405,36 @@ You can convert once using 'deferIndex' and 'revealIndex' whenever you need your application specific index type. No need for e.g. @Storable (Index sh)@, because 'Int' is already 'Storable'.+You get 'Indexed' and 'InvIndexed' instances+without the need for an 'Index' type.+The disadvantage is:+A deferred index should be bound to a specific shape, but this is not checked.+That is, you may obtain a deferred index for one shape+and accidentally abuse it for another shape without a warning.++Example:++> Shape> let sh2 = (ZeroBased (2::Int), ZeroBased (2::Int))+> Shape> let sh3 = (ZeroBased (3::Int), ZeroBased (3::Int))+> Shape> offset sh3 $ indexFromOffset sh2 3+> 4+> Shape> offset (Deferred sh3) $ indexFromOffset (Deferred sh2) 3+> 3 -} newtype Deferred sh = Deferred sh    deriving (Eq, Show) -newtype DeferredIndex ix = DeferredIndex Int-   deriving (Eq, Show)+{- |+'DeferredIndex' has an 'Ord' instance+that is based on the storage order in memory.+This way, you can put 'DeferredIndex' values+in a 'Set' or use them as keys in a 'Map'+even if @Index sh@ has no 'Ord' instance.+The downside is, that the ordering of @DeferredIndex sh@+may differ from the one of @Index sh@.+-}+newtype DeferredIndex sh = DeferredIndex Int+   deriving (Eq, Ord, Show)  instance (NFData sh) => NFData (Deferred sh) where    rnf (Deferred sh) = rnf sh@@ -388,25 +444,34 @@    uncheckedSize (Deferred sh) = uncheckedSize sh  instance (C sh) => Indexed (Deferred sh) where-   type Index (Deferred sh) = DeferredIndex (Index sh)+   type Index (Deferred sh) = DeferredIndex sh    indices (Deferred sh) = map DeferredIndex $ take (size sh) [0 ..]    offset (Deferred sh) (DeferredIndex k) = offset (ZeroBased $ size sh) k    uncheckedOffset _ (DeferredIndex k) = k+   sizeOffset (Deferred sh) =+      mapSnd (\offs (DeferredIndex k) -> offs k) $+      sizeOffset (ZeroBased $ size sh)+   uncheckedSizeOffset (Deferred sh) =+      mapSnd (\ _offs (DeferredIndex k) -> k) $+      uncheckedSizeOffset (ZeroBased $ size sh)    inBounds (Deferred sh) (DeferredIndex k) =       inBounds (ZeroBased $ size sh) k  instance (C sh) => InvIndexed (Deferred sh) where-   indexFromOffset sh k =+   indexFromOffset (Deferred sh) k =       DeferredIndex $ indexFromOffset (ZeroBased $ size sh) k    uncheckedIndexFromOffset _sh = DeferredIndex -deferIndex :: (Indexed sh, Index sh ~ ix) => sh -> ix -> DeferredIndex ix+deferIndex :: (Indexed sh, Index sh ~ ix) => sh -> ix -> DeferredIndex sh deferIndex sh ix = DeferredIndex $ offset sh ix -revealIndex :: (InvIndexed sh, Index sh ~ ix) => sh -> DeferredIndex ix -> ix+revealIndex :: (InvIndexed sh, Index sh ~ ix) => sh -> DeferredIndex sh -> ix revealIndex sh (DeferredIndex ix) = indexFromOffset sh ix -instance Storable (DeferredIndex ix) where+instance (Static sh) => Static (Deferred sh) where+   static = Deferred static++instance Storable (DeferredIndex sh) where    {-# INLINE sizeOf #-}    {-# INLINE alignment #-}    {-# INLINE peek #-}@@ -418,6 +483,30 @@   +instance (C sh) => C (Tagged s sh) where+   size (Tagged sh) = size sh+   uncheckedSize (Tagged sh) = uncheckedSize sh++instance (Indexed sh) => Indexed (Tagged s sh) where+   type Index (Tagged s sh) = Tagged s (Index sh)+   indices (Tagged sh) = map Tagged $ indices sh+   offset (Tagged sh) (Tagged k) = offset sh k+   uncheckedOffset (Tagged sh) (Tagged k) = uncheckedOffset sh k+   sizeOffset (Tagged sh) = mapSnd (. unTagged) $ sizeOffset sh+   uncheckedSizeOffset (Tagged sh) =+      mapSnd (. unTagged) $ uncheckedSizeOffset sh+   inBounds (Tagged sh) (Tagged k) = inBounds sh k++instance (InvIndexed sh) => InvIndexed (Tagged s sh) where+   indexFromOffset (Tagged sh) k = Tagged $ indexFromOffset sh k+   uncheckedIndexFromOffset (Tagged sh) k =+      Tagged $ uncheckedIndexFromOffset sh k++instance (Static sh) => Static (Tagged s sh) where+   static = Tagged static+++ {- | Row-major composition of two dimensions. -}@@ -452,7 +541,10 @@    uncheckedIndexFromOffset (sh0,sh1) k =       runInvIndex k $ liftA2 (,) (uncheckedPickLastIndex sh0) (pickIndex sh1) +instance (Static sh0, Static sh1) => Static (sh0,sh1) where+   static = (static, static) + instance (C sh0, C sh1, C sh2) => C (sh0,sh1,sh2) where    size (sh0,sh1,sh2) = size sh0 * size sh1 * size sh2    uncheckedSize (sh0,sh1,sh2) =@@ -493,6 +585,9 @@       runInvIndex k $       liftA3 (,,) (uncheckedPickLastIndex sh0) (pickIndex sh1) (pickIndex sh2) +instance (Static sh0, Static sh1, Static sh2) => Static (sh0,sh1,sh2) where+   static = (static, static, static)+ runInvIndex :: s -> Back.Backwards (MS.State s) a -> a runInvIndex k = flip MS.evalState k . Back.forwards @@ -545,8 +640,16 @@    Triangular {       triangularPart :: part,       triangularSize :: size-   } deriving (Eq, Show)+   } deriving (Show) +newtype Equal part = Equal {getEqual :: part -> part -> Bool}++equalPart :: (TriangularPart part) => part -> part -> Bool+equalPart = getEqual $ switchTriangularPart (Equal (==)) (Equal (==))++instance (TriangularPart part, Eq size) => Eq (Triangular part size) where+   x==y  =  compose2 equalPart triangularPart x y && equating triangularSize x y+ type LowerTriangular = Triangular Lower type UpperTriangular = Triangular Upper @@ -646,7 +749,16 @@ triangleRootDouble = triangleRoot . fromIntegral  +instance+   (TriangularPart part, Static size) =>+      Static (Triangular part size) where+   static = Triangular autoPart static +autoPart :: (TriangularPart part) => part+autoPart = runIdentity $ switchTriangularPart (Identity Lower) (Identity Upper)+++ infixr 5 :+:  data sh0:+:sh1 = sh0:+:sh1@@ -691,3 +803,6 @@       in if k < pivot             then Left $ uncheckedIndexFromOffset sh0 k             else Right $ uncheckedIndexFromOffset sh1 $ k-pivot++instance (Static sh0, Static sh1) => Static (sh0:+:sh1) where+   static = static:+:static
src/Data/Array/Comfort/Storable.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE TypeFamilies #-} module Data.Array.Comfort.Storable (    Array,    shape,@@ -6,56 +7,72 @@     (!),    Array.toList,+   Array.vectorFromList,+   toAssociations,    fromList,    fromMap,-   Array.vectorFromList,+   fromContainer,+   toContainer,    sample,    fromBoxed,    toBoxed,     Array.map,    Array.mapWithIndex,+   zipWith,    (//),    accumulate,    fromAssociations,++   Array.singleton,+   Array.append,+   Array.take, Array.drop,+   Array.takeLeft, Array.takeRight, Array.split,++   Array.sum, Array.product,+   minimum, argMinimum,+   maximum, argMaximum,+   limits,+   Array.foldl,+   foldl1,+   foldMap,    ) where  import qualified Data.Array.Comfort.Storable.Mutable.Unchecked as MutArrayNC import qualified Data.Array.Comfort.Storable.Mutable as MutArray import qualified Data.Array.Comfort.Storable.Unchecked as Array+import qualified Data.Array.Comfort.Storable.Memory as Memory+import qualified Data.Array.Comfort.Container as Container import qualified Data.Array.Comfort.Boxed as BoxedArray+import qualified Data.Array.Comfort.Check as Check import qualified Data.Array.Comfort.Shape as Shape-import Data.Array.Comfort.Storable.Unchecked (Array)+import Data.Array.Comfort.Storable.Unchecked (Array(Array)) +import System.IO.Unsafe (unsafePerformIO) import Foreign.Storable (Storable)+import Foreign.ForeignPtr (withForeignPtr)  import Control.Monad.ST (runST)  import qualified Data.Map as Map+import qualified Data.Foldable as Fold import qualified Data.List as List+import qualified Data.Tuple.Strict as StrictTuple import Data.Map (Map) import Data.Set (Set) import Data.Foldable (forM_)--import Text.Printf (printf)+import Data.Semigroup+         (Semigroup, (<>), Min(Min,getMin), Max(Max,getMax), Arg(Arg)) -import Prelude hiding (map)+import Prelude2010 hiding (map, zipWith, foldl1, minimum, maximum)+import Prelude ()   shape :: Array sh a -> sh shape = Array.shape  reshape :: (Shape.C sh0, Shape.C sh1) => sh1 -> Array sh0 a -> Array sh1 a-reshape sh1 arr =-   let n0 = Shape.size $ shape arr-       n1 = Shape.size sh1-   in if n0 == n1-         then Array.reshape sh1 arr-         else error $-              printf-                 ("Array.Comfort.Storable.reshape: " ++-                  "different sizes of old (%d) and new (%d) shape")-                 n0 n1+reshape = Check.reshape "Storable" shape Array.reshape  mapShape ::    (Shape.C sh0, Shape.C sh1) => (sh0 -> sh1) -> Array sh0 a -> Array sh1 a@@ -68,6 +85,14 @@ fromMap :: (Ord k, Storable a) => Map k a -> Array (Set k) a fromMap m = fromList (Map.keysSet m) (Map.elems m) +fromContainer ::+   (Container.C f, Storable a) => f a -> Array (Container.Shape f) a+fromContainer xs = fromList (Container.toShape xs) (Fold.toList xs)++toContainer ::+   (Container.C f, Storable a) => Array (Container.Shape f) a -> f a+toContainer arr = Container.fromList (Array.shape arr) (Array.toList arr)+ sample ::    (Shape.Indexed sh, Storable a) => sh -> (Shape.Index sh -> a) -> Array sh a sample sh f = Array.fromList sh $ List.map f $ Shape.indices sh@@ -79,7 +104,11 @@ toBoxed :: (Shape.C sh, Storable a) => Array sh a -> BoxedArray.Array sh a toBoxed arr = BoxedArray.fromList (Array.shape arr) $ Array.toList arr +toAssociations ::+   (Shape.Indexed sh, Storable a) => Array sh a -> [(Shape.Index sh, a)]+toAssociations arr = zip (Shape.indices $ shape arr) (Array.toList arr) + infixl 9 !  (!) :: (Shape.Indexed sh, Storable a) => Array sh a -> Shape.Index sh -> a@@ -88,6 +117,14 @@    MutArray.read marr ix)  +zipWith ::+   (Shape.C sh, Eq sh, Storable a, Storable b, Storable c) =>+   (a -> b -> c) -> Array sh a -> Array sh b -> Array sh c+zipWith f a b =+   if shape a == shape b+      then Array.zipWith f a b+      else error "zipWith: shapes mismatch"+ (//) ::    (Shape.Indexed sh, Storable a) =>    Array sh a -> [(Shape.Index sh, a)] -> Array sh a@@ -106,8 +143,53 @@  fromAssociations ::    (Shape.Indexed sh, Storable a) =>-   sh -> a -> [(Shape.Index sh, a)] -> Array sh a-fromAssociations sh a xs = runST (do+   a -> sh -> [(Shape.Index sh, a)] -> Array sh a+fromAssociations a sh xs = runST (do    marr <- MutArray.new sh a    forM_ xs $ uncurry $ MutArray.write marr    MutArrayNC.unsafeFreeze marr)++++{- |+It is a checked error if the vector is empty.+-}+minimum, maximum :: (Shape.C sh, Storable a, Ord a) => Array sh a -> a+minimum = foldl1 min+maximum = foldl1 max++{-# INLINE foldl1 #-}+foldl1 :: (Shape.C sh, Storable a) => (a -> a -> a) -> Array sh a -> a+foldl1 op (Array sh x) = unsafePerformIO $+   withForeignPtr x $ \xPtr ->+      Memory.foldl1 (const id) op (Shape.size sh) xPtr 1++{- |+> limits x = (minimum x, maximum x)+-}+limits :: (Shape.C sh, Storable a, Ord a) => Array sh a -> (a,a)+limits = StrictTuple.mapPair (getMin, getMax) . foldMap (\x -> (Min x, Max x))++{-# INLINE foldMap #-}+foldMap ::+   (Shape.C sh, Storable a, Ord a, Semigroup m) => (a -> m) -> Array sh a -> m+foldMap f (Array sh x) = unsafePerformIO $+   withForeignPtr x $ \xPtr ->+      Memory.foldl1 (const f) (<>) (Shape.size sh) xPtr 1+++argMinimum, argMaximum ::+   (Shape.InvIndexed sh, Shape.Index sh ~ ix, Storable a, Ord a) =>+   Array sh a -> (ix,a)+argMinimum xs = unArg xs $ getMin $ foldMapWithIndex (\k x -> Min (Arg x k)) xs+argMaximum xs = unArg xs $ getMax $ foldMapWithIndex (\k x -> Max (Arg x k)) xs++unArg ::+   (Shape.InvIndexed sh) => Array sh a -> Arg a Int -> (Shape.Index sh, a)+unArg xs (Arg x k) = (Shape.indexFromOffset (Array.shape xs) k, x)++{-# INLINE foldMapWithIndex #-}+foldMapWithIndex ::+   (Shape.C sh, Storable a, Semigroup m) => (Int -> a -> m) -> Array sh a -> m+foldMapWithIndex f (Array sh x) = unsafePerformIO $+   withForeignPtr x $ \xPtr -> Memory.foldl1 f (<>) (Shape.size sh) xPtr 1
+ src/Data/Array/Comfort/Storable/Memory.hs view
@@ -0,0 +1,29 @@+module Data.Array.Comfort.Storable.Memory where++import Foreign.Marshal.Array (advancePtr)+import Foreign.Ptr (Ptr)+import Foreign.Storable (Storable, peek, peekElemOff)++import Control.Monad (foldM)++import Prelude hiding (foldl, foldl1)+++{-# INLINE foldl #-}+foldl ::+   (Storable a) => (Int -> b -> a -> b) -> b -> Int -> Ptr a -> Int -> IO b+foldl op b n xPtr incx =+   foldM (\x k -> do y <- peekElemOff xPtr (k*incx); return $! op k x y) b $+   take n $ iterate (+1) 0++{-# INLINE foldl1 #-}+foldl1 ::+   (Storable a) =>+   (Int -> a -> b) -> (b -> b -> b) -> Int -> Ptr a -> Int -> IO b+foldl1 f op n xPtr incx =+   if n<1+      then error "foldl1: empty vector"+      else do+         x0 <- peek xPtr+         foldl (\k b a -> op b (f (k+1) a))+            (f 0 x0) (n-1) (advancePtr xPtr incx) incx
src/Data/Array/Comfort/Storable/Private.hs view
@@ -23,11 +23,15 @@    }  instance (Shape.C sh, Show sh, Storable a, Show a) => Show (Array sh a) where-   show arr = runST (MutArray.show =<< unsafeThaw arr)+   showsPrec p arr =+      showParen (p>10) $ showString $ runST (MutArray.show =<< unsafeThaw arr)  instance (NFData sh) => NFData (Array sh a) where    rnf (Array sh fptr) = seq fptr (rnf sh) +instance (Shape.C sh, Eq sh, Storable a, Eq a) => Eq (Array sh a) where+   a@(Array sha _) == b@(Array shb _)  =  sha==shb && toList a == toList b+ reshape :: sh1 -> Array sh0 a -> Array sh1 a reshape sh (Array _ fptr) = Array sh fptr @@ -68,8 +72,8 @@  fromAssociations ::    (Shape.Indexed sh, Storable a) =>-   sh -> a -> [(Shape.Index sh, a)] -> Array sh a-fromAssociations sh a xs = runST (do+   a -> sh -> [(Shape.Index sh, a)] -> Array sh a+fromAssociations a sh xs = runST (do    marr <- MutArray.new sh a    forM_ xs $ uncurry $ MutArray.write marr    unsafeFreeze marr)
src/Data/Array/Comfort/Storable/Unchecked.hs view
@@ -1,11 +1,12 @@ {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {- | The functions in this module miss any bound checking. -} module Data.Array.Comfort.Storable.Unchecked (    Priv.Array(Array, shape, buffer),    Priv.reshape,-   Priv.mapShape,+   mapShape,     (Priv.!),    unsafeCreate,@@ -17,26 +18,41 @@     map,    mapWithIndex,+   zipWith,    (Priv.//),    Priv.accumulate,    Priv.fromAssociations,++   singleton,+   append,+   take, drop,+   takeLeft, takeRight, split,++   sum, product,+   foldl,    ) where  import qualified Data.Array.Comfort.Storable.Unchecked.Monadic as Monadic import qualified Data.Array.Comfort.Storable.Private as Priv+import qualified Data.Array.Comfort.Storable.Memory as Memory import qualified Data.Array.Comfort.Shape as Shape-import Data.Array.Comfort.Storable.Private (Array(Array))+import Data.Array.Comfort.Storable.Private (Array(Array), mapShape)+import Data.Array.Comfort.Shape ((:+:)((:+:))) -import Foreign.Marshal.Array (advancePtr)+import System.IO.Unsafe (unsafePerformIO)+import Foreign.Marshal.Array (copyArray, advancePtr) import Foreign.Storable (Storable, poke, peek) import Foreign.ForeignPtr (withForeignPtr) import Foreign.Ptr (Ptr)  import Control.Monad.ST (runST)+import Control.Applicative (liftA2) -import Prelude hiding (map)+import qualified Data.List as List +import Prelude hiding (map, zipWith, foldl, take, drop, sum, product) + unsafeCreate ::    (Shape.C sh, Storable a) =>    sh -> (Ptr a -> IO ()) -> Array sh a@@ -60,8 +76,8 @@ map f (Array sh a) =    unsafeCreate sh $ \dstPtr ->    withForeignPtr a $ \srcPtr ->-   sequence_ $ take (Shape.size sh) $-      zipWith+   sequence_ $ List.take (Shape.size sh) $+      List.zipWith          (\src dst -> poke dst . f =<< peek src)          (iterate (flip advancePtr 1) srcPtr)          (iterate (flip advancePtr 1) dstPtr)@@ -73,8 +89,84 @@    unsafeCreate sh $ \dstPtr ->    withForeignPtr a $ \srcPtr ->    sequence_ $-      zipWith3+      List.zipWith3          (\ix src dst -> poke dst . f ix =<< peek src)          (Shape.indices sh)          (iterate (flip advancePtr 1) srcPtr)          (iterate (flip advancePtr 1) dstPtr)++zipWith ::+   (Shape.C sh, Storable a, Storable b, Storable c) =>+   (a -> b -> c) -> Array sh a -> Array sh b -> Array sh c+zipWith f (Array _sh a) (Array sh b) =+   unsafeCreate sh $ \dstPtr ->+   withForeignPtr a $ \srcAPtr ->+   withForeignPtr b $ \srcBPtr ->+   sequence_ $ List.take (Shape.size sh) $+      zipWith3+         (\srcA srcB dst -> poke dst =<< liftA2 f (peek srcA) (peek srcB))+         (iterate (flip advancePtr 1) srcAPtr)+         (iterate (flip advancePtr 1) srcBPtr)+         (iterate (flip advancePtr 1) dstPtr)+++singleton :: (Storable a) => a -> Array () a+singleton a = unsafeCreate () $ flip poke a++append ::+   (Shape.C shx, Shape.C shy, Storable a) =>+   Array shx a -> Array shy a -> Array (shx:+:shy) a+append (Array shX x) (Array shY y) =+   unsafeCreate (shX:+:shY) $ \zPtr ->+   withForeignPtr x $ \xPtr ->+   withForeignPtr y $ \yPtr -> do+      let sizeX = Shape.size shX+      let sizeY = Shape.size shY+      copyArray zPtr xPtr sizeX+      copyArray (advancePtr zPtr sizeX) yPtr sizeY++take, drop ::+   (Integral n, Storable a) =>+   n -> Array (Shape.ZeroBased n) a -> Array (Shape.ZeroBased n) a+take n = takeLeft . splitN n+drop n = takeRight . splitN n++splitN ::+   (Integral n, Storable a) =>+   n -> Array (Shape.ZeroBased n) a ->+   Array (Shape.ZeroBased n :+: Shape.ZeroBased n) a+splitN n = mapShape (Shape.zeroBasedSplit n)++takeLeft ::+   (Shape.C sh0, Shape.C sh1, Storable a) =>+   Array (sh0:+:sh1) a -> Array sh0 a+takeLeft (Array (sh0 :+: _sh1) x) =+   unsafeCreateWithSize sh0 $ \k yPtr ->+   withForeignPtr x $ \xPtr -> copyArray yPtr xPtr k++takeRight ::+   (Shape.C sh0, Shape.C sh1, Storable a) =>+   Array (sh0:+:sh1) a -> Array sh1 a+takeRight (Array (sh0:+:sh1) x) =+   unsafeCreateWithSize sh1 $ \k yPtr ->+   withForeignPtr x $ \xPtr ->+      copyArray yPtr (advancePtr xPtr (Shape.size sh0)) k++split ::+   (Shape.C sh0, Shape.C sh1, Storable a) =>+   Array (sh0:+:sh1) a -> (Array sh0 a, Array sh1 a)+split x = (takeLeft x, takeRight x)++++sum :: (Shape.C sh, Storable a, Num a) => Array sh a -> a+sum = foldl (+) 0++product :: (Shape.C sh, Storable a, Num a) => Array sh a -> a+product = foldl (*) 1++{-# INLINE foldl #-}+foldl :: (Shape.C sh, Storable a) => (b -> a -> b) -> b -> Array sh a -> b+foldl op a (Array sh x) = unsafePerformIO $+   withForeignPtr x $ \xPtr ->+      Memory.foldl (const op) a (Shape.size sh) xPtr 1
test/Main.hs view
@@ -2,6 +2,7 @@ module Main where  import qualified Test.Shape as TestShape+import qualified Test.Storable as TestStorable import Test.Utility (prefix)  import qualified Test.QuickCheck as QC@@ -11,4 +12,5 @@ main =    mapM_ (\(name,prop) -> putStr (name ++ ": ") >> QC.quickCheck prop) $    prefix "Shape" TestShape.tests +++   prefix "Storable" TestStorable.tests ++    []
test/Test/Shape.hs view
@@ -10,11 +10,15 @@ import Control.Applicative (liftA2, liftA3)  import qualified Data.Set as Set+import Data.Tagged (Tagged(Tagged))   genZeroBased :: Int -> QC.Gen (Shape.ZeroBased Int) genZeroBased n = fmap Shape.ZeroBased $ QC.choose (0,n) +tag :: sh -> Tagged Ordering sh+tag = Tagged+ tests :: [(String, QC.Property)] tests =    prefix "ZeroBased"@@ -41,6 +45,10 @@        fmap Set.fromList (QC.listOf (QC.choose ('a','z')))) ++    prefix "Deferred Shifted"       (ShapeTest.tests $ fmap Shape.Deferred $+       liftA2 Shape.Shifted+         (QC.choose (-10,10::Int)) (QC.choose (0,10::Int))) +++   prefix "Tagged Shifted"+      (ShapeTest.tests $ fmap tag $        liftA2 Shape.Shifted          (QC.choose (-10,10::Int)) (QC.choose (0,10::Int))) ++    prefix "Pair"
+ test/Test/Storable.hs view
@@ -0,0 +1,93 @@+module Test.Storable where++import qualified Data.Array.Comfort.Storable as Array+import qualified Data.Array.Comfort.Shape as Shape+import Data.Array.Comfort.Storable (Array, (!))++import Foreign.Storable (Storable)++import qualified Test.QuickCheck as QC+import Test.ChasingBottoms.IsBottom (isBottom)++import Control.Applicative ((<$>))++import Data.Word (Word16)+++type ShapeInt = Shape.ZeroBased Int++genArray :: QC.Gen (Array ShapeInt Word16)+genArray = Array.vectorFromList <$> QC.arbitrary+++singleton :: (Storable a, Eq a) => a -> Bool+singleton x  =  x == Array.singleton x ! ()++appendTakeDrop ::+   (Storable a, Eq a) =>+   QC.NonNegative Int -> Array ShapeInt a -> Bool+appendTakeDrop (QC.NonNegative n) x =+   x ==+   Array.mapShape (Shape.ZeroBased . Shape.size)+      (Array.append (Array.take n x) (Array.drop n x))++takeLeftRightAppend ::+   (Storable a, Eq a) =>+   Array ShapeInt a -> Array ShapeInt a -> Bool+takeLeftRightAppend x y =+   let xy = Array.append x y+   in x == Array.takeLeft xy  &&  y == Array.takeRight xy+++sumList :: (Storable a, Num a, Eq a) => Array ShapeInt a -> Bool+sumList xs  =  Array.sum xs == sum (Array.toList xs)++productList :: (Storable a, Num a, Eq a) => Array ShapeInt a -> Bool+productList xs  =  Array.product xs == product (Array.toList xs)+++withNonEmpty ::+   (Array ShapeInt a -> b) ->+   (b -> Array ShapeInt a -> Bool) ->+   Array ShapeInt a -> Bool+withNonEmpty f law xs =+   let x = f xs+   in if Array.shape xs == Shape.ZeroBased 0+         then isBottom x+         else law x xs++minimumList :: (Storable a, Ord a) => Array ShapeInt a -> Bool+minimumList =+   withNonEmpty Array.minimum $ \x xs -> x == minimum (Array.toList xs)++maximumList :: (Storable a, Ord a) => Array ShapeInt a -> Bool+maximumList =+   withNonEmpty Array.maximum $ \x xs -> x == maximum (Array.toList xs)++limitsMinimumMaximum :: (Storable a, Ord a) => Array ShapeInt a -> Bool+limitsMinimumMaximum =+   withNonEmpty Array.limits $+      \xe xs -> xe == (Array.minimum xs, Array.maximum xs)+++tests :: [(String, QC.Property)]+tests =+   ("singleton", QC.property (singleton . (id :: Word16 -> Word16))) :+   ("appendTakeDrop",+      QC.forAll QC.arbitrary $ \n ->+      QC.forAll genArray $ \xs -> appendTakeDrop n xs) :+   ("takeLeftRightAppend",+      QC.forAll genArray $ \xs ->+      QC.forAll genArray $ \ys -> takeLeftRightAppend xs ys) :++   ("sum",+      QC.forAll genArray sumList) :+   ("product",+      QC.forAll genArray productList) :+   ("minimum",+      QC.forAll genArray minimumList) :+   ("maximum",+      QC.forAll genArray maximumList) :+   ("limitsMinimumMaximum",+      QC.forAll genArray limitsMinimumMaximum) :+   []