phasechange (empty) → 0.1
raw patch · 8 files changed
+573/−0 lines, 8 filesdep +arraydep +basedep +ghc-primsetup-changed
Dependencies added: array, base, ghc-prim, monad-st, primitive, vector
Files
- Data/PhaseChange.hs +37/−0
- Data/PhaseChange/Impl.hs +16/−0
- Data/PhaseChange/Instances.hs +141/−0
- Data/PhaseChange/Internal.hs +247/−0
- Data/PhaseChange/Unsafe.hs +21/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- phasechange.cabal +79/−0
+ Data/PhaseChange.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE TypeFamilies, Trustworthy #-}++-- | This module provides referentially transparent functions for working with PhaseChangeable data.+-- For functions that can break referential transparency, see "Data.PhaseChange.Unsafe".+-- If you want to write instances, see "Data.PhaseChange.Impl".+module Data.PhaseChange+ (+-- * @PhaseChange@ class+ PhaseChange (type Thawed, type Frozen),+-- * Assymetric constraint synonyms+ Mutable, Immutable,+-- * Functions+ thaw, freeze, copy, frozen, updateWith,+-- * Newtypes for shifting the \'s' type variable to the last position+ M1(..), M2(..),+-- * Convenience functions for working with @'M1'@+ thaw1, freeze1, copy1, frozen1, updateWith1,+-- * Convenience functions for working with @'M2'@+ thaw2, freeze2, copy2, frozen2, updateWith2++-- * A note on Safe Haskell+-- | Much like @Data.Typeable@, this module provides a class along with functions using it which are+-- safe as long as instances of the class play by the rules. This module is declared @Trustworthy@,+-- while "Data.PhaseChange.Impl" is @Unsafe@, so modules providing instances must necessarily also+-- be @Trustworthy@ (or @Unsafe@). It is up to the consumer to decide whether modules declaring+-- themselves @Trustworthy@ are actually to be trusted. The combination of any number of+-- @Trustworthy@ modules is safe only as long as all of them are.++-- * A note on GHC+-- | GHC doesn't handle the combination of @SPECIALIZE@ pragmas and type families very well. It appears+-- to be impossible to write them in a way that works with both GHC 7.2 and GHC 7.4. So here the ones+-- for freeze, thaw, etc. work with GHC 7.4 and spit a racket of warnings with 7.2. That's life.+ )+ where++import Data.PhaseChange.Internal+import Data.PhaseChange.Instances ()
+ Data/PhaseChange/Impl.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}++#if __GLASGOW_HASKELL__ >= 704+{-# LANGUAGE Unsafe #-}+#endif++-- | This module allows you to write instances for PhaseChangeable types.+-- To work with PhaseChangeable data, see "Data.PhaseChange". For unsafe functions, see "Data.PhaseChange.Unsafe".+module Data.PhaseChange.Impl+ (+ PhaseChange(..), M1(..), M2(..)+ )+ where++import Data.PhaseChange.Internal+import Data.PhaseChange.Instances ()
+ Data/PhaseChange/Instances.hs view
@@ -0,0 +1,141 @@+{-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleContexts, FlexibleInstances, RankNTypes, MagicHash, UnboxedTuples #-}++{-# OPTIONS_HADDOCK hide #-}++{-# OPTIONS_GHC -fno-warn-orphans -fno-warn-name-shadowing -fno-warn-unused-binds #-}++module Data.PhaseChange.Instances () where++import Data.PhaseChange.Internal+import Control.Monad+import Control.Monad.Primitive+import Control.Monad.ST+import Unsafe.Coerce+import GHC.Exts++-- they sure made a big mess out of the Array modules...+import Data.Primitive.Array as Prim+import Data.Primitive.ByteArray as Prim+import Data.Array as Arr (Array)+import Data.Array.ST as Arr (STArray, STUArray)+import Data.Array.Unboxed as Arr (UArray)+import Data.Array.IArray as Arr (IArray, Ix)+import Data.Array.MArray as Arr (MArray, mapArray)+import Data.Array.Unsafe as Arr (unsafeThaw, unsafeFreeze)+import Data.Vector as Vec+import Data.Vector.Primitive as PVec+import Data.Vector.Unboxed as UVec+import Data.Vector.Storable as SVec+import Data.Vector.Generic.Mutable as GVec++cloneMutableArray :: (PrimMonad m, s ~ PrimState m) => MutableArray s a -> Int -> Int -> m (MutableArray s a)+cloneMutableArray (MutableArray a#) (I# begin#) (I# size#) =+ primitive $ \s# -> case cloneMutableArray# a# begin# size# s#+ of (# s'#, a'# #) -> (# s'#, MutableArray a'# #)++sizeofMutableArray :: MutableArray s a -> Int+sizeofMutableArray (MutableArray a#) = I# (sizeofMutableArray# a#)++-- * primitive++-- | Data.Primitive.ByteArray+instance PhaseChange Prim.ByteArray Prim.MutableByteArray where+ type Thawed Prim.ByteArray = Prim.MutableByteArray+ type Frozen Prim.MutableByteArray = Prim.ByteArray+ unsafeThawImpl = unsafeThawByteArray+ unsafeFreezeImpl = unsafeFreezeByteArray+ copyImpl old = do+ let size = sizeofMutableByteArray old+ new <- newByteArray size+ copyMutableByteArray new 0 old 0 size+ return new++-- | Data.Primitive.Array+instance PhaseChange (Prim.Array a) (M1 Prim.MutableArray a) where+ type Thawed (Prim.Array a) = M1 Prim.MutableArray a+ type Frozen (M1 Prim.MutableArray a) = Prim.Array a+ unsafeThawImpl = liftM M1 . unsafeThawArray+ unsafeFreezeImpl = unsafeFreezeArray . unM1+ copyImpl (M1 a) = liftM M1 $ cloneMutableArray a 0 (sizeofMutableArray a)+++-- * array++-- NOTE+-- for the Array types, we have to use a hack: we want to write "forall s. MArray (STArray s) a (ST s)"+-- in the instance declaration, but we can't do that. our hack is that we have an unexported type, S,+-- and we write "MArray (STArray S) a (ST S)" instead. because S is not exported, the only way the+-- constraint can be satisfied is if it is true forall s. and then we use unsafeCoerce.+-- (this trick is borrowed from Edward Kmett's constraints library)++-- capture and store the evidence for an MArray constraint in CPS form+type WithMArray stArray s a = forall r. (MArray (stArray s) a (ST s) => r) -> r++-- capture locally available evidence and store it+mArray :: MArray (stArray s) a (ST s) => WithMArray stArray s a+mArray a = a++-- see NOTE above. do not export!+newtype S = S S++-- if we know MArray for S, it must be true forall s. make it so.+anyS :: WithMArray stArray S a -> WithMArray stArray s a+anyS = unsafeCoerce++-- from locally available evidence of MArray for S, produce evidence we can use+-- for any s. the first argument is just a dummy to bring type variables into scope,+-- chosen to be convenient for the particular use sites that we have.+hack :: MArray (stArray S) a (ST S) => ST s (M2 stArray i a s) -> WithMArray stArray s a+hack _ = anyS mArray++-- | Data.Array+instance (Ix i, IArray Arr.Array a, MArray (Arr.STArray S) a (ST S)) => PhaseChange (Arr.Array i a) (M2 Arr.STArray i a) where+ type Thawed (Arr.Array i a) = M2 Arr.STArray i a+ type Frozen (M2 Arr.STArray i a) = Arr.Array i a+ unsafeThawImpl a = r where r = hack r (liftM M2 $ Arr.unsafeThaw a)+ unsafeFreezeImpl a = hack (return a) (Arr.unsafeFreeze $ unM2 a)+ copyImpl a = hack (return a) (liftM M2 . mapArray id . unM2 $ a)++-- | Data.Array.Unboxed+instance (Ix i, IArray Arr.UArray a, MArray (Arr.STUArray S) a (ST S)) => PhaseChange (Arr.UArray i a) (M2 Arr.STUArray i a) where+ type Thawed (Arr.UArray i a) = M2 Arr.STUArray i a+ type Frozen (M2 Arr.STUArray i a) = Arr.UArray i a+ unsafeThawImpl a = r where r = hack r (liftM M2 $ Arr.unsafeThaw a)+ unsafeFreezeImpl a = hack (return a) (Arr.unsafeFreeze $ unM2 a)+ copyImpl a = hack (return a) (liftM M2 . mapArray id . unM2 $ a)+++-- * vector++-- | Data.Vector+instance PhaseChange (Vec.Vector a) (M1 Vec.MVector a) where+ type Thawed (Vec.Vector a) = M1 Vec.MVector a+ type Frozen (M1 Vec.MVector a) = Vec.Vector a+ unsafeThawImpl = liftM M1 . Vec.unsafeThaw+ unsafeFreezeImpl = Vec.unsafeFreeze . unM1+ copyImpl = liftM M1 . GVec.clone . unM1++-- | Data.Vector.Storable+instance Storable a => PhaseChange (SVec.Vector a) (M1 SVec.MVector a) where+ type Thawed (SVec.Vector a) = M1 SVec.MVector a+ type Frozen (M1 SVec.MVector a) = SVec.Vector a+ unsafeThawImpl = liftM M1 . SVec.unsafeThaw+ unsafeFreezeImpl = SVec.unsafeFreeze . unM1+ copyImpl = liftM M1 . GVec.clone . unM1++-- | Data.Vector.Primitive+instance Prim a => PhaseChange (PVec.Vector a) (M1 PVec.MVector a) where+ type Thawed (PVec.Vector a) = M1 PVec.MVector a+ type Frozen (M1 PVec.MVector a) = PVec.Vector a+ unsafeThawImpl = liftM M1 . PVec.unsafeThaw+ unsafeFreezeImpl = PVec.unsafeFreeze . unM1+ copyImpl = liftM M1 . GVec.clone . unM1++-- | Data.Vector.Unboxed+instance Unbox a => PhaseChange (UVec.Vector a) (M1 UVec.MVector a) where+ type Thawed (UVec.Vector a) = M1 UVec.MVector a+ type Frozen (M1 UVec.MVector a) = UVec.Vector a+ unsafeThawImpl = liftM M1 . UVec.unsafeThaw+ unsafeFreezeImpl = UVec.unsafeFreeze . unM1+ copyImpl = liftM M1 . GVec.clone . unM1+
+ Data/PhaseChange/Internal.hs view
@@ -0,0 +1,247 @@+{-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleContexts, Rank2Types, CPP #-}++#if __GLASGOW_HASKELL__ >= 704+{-# LANGUAGE ConstraintKinds #-}+#else+{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}+#endif++{-# OPTIONS_HADDOCK hide #-}++module Data.PhaseChange.Internal where++import Control.Monad+import Control.Monad.ST (ST, runST)+import Control.Monad.ST.Class+import GHC.Exts (RealWorld)+--import Control.Newtype++-- | The @PhaseChange@ class ties together types which provide a mutable and an immutable view+-- on the same data. The mutable type must have a phantom type parameter representing the+-- state thread it is being used in. Many types have this type parameter in the wrong place+-- (not at the end): instances for them can be provided using the @'M1'@ and @'M2'@ newtypes.+class (Thawed imm ~ mut, Frozen mut ~ imm) => PhaseChange (imm :: *) (mut :: * -> *) where+ type Thawed imm :: * -> *+ type Frozen mut :: *+ -- | Should return the same data it got as input, viewed as a mutable type, making no+ -- changes.+ unsafeThawImpl :: imm -> ST s (Thawed imm s)+ -- | Should return the same data it got as input, viewed as an immutable type, making no+ -- changes.+ unsafeFreezeImpl :: mut s -> ST s (Frozen mut)+ -- | Should make a perfect copy of the input argument, leaving nothing shared between+ -- the original and the copy, and making no other changes.+ copyImpl :: mut s -> ST s (mut s)++-- you might think that unsafeThaw and unsafeFreeze (and for that matter thaw) don't need to+-- be monadic, because after all they're just conceptually wrapping/unwrapping newtypes, and+-- the argument of thaw is immutable so evaluating lazily should be fine.+-- two things get in the way:+-- - GHC's unsafeFreeze/unsafeThaw aren't actually pure, they mutate some bits to let the+-- garbage collector know what's mutable and what's not; and+-- - while it wouldn't break referential transparency directly, it would if you were to use+-- the result of thaw/unsafeThaw in two different calls to runST. so we can't allow that.+++#if __GLASGOW_HASKELL__ >= 704+type Mutable mut = PhaseChange (Frozen mut) mut+#else+class PhaseChange (Frozen mut) mut => Mutable mut+instance PhaseChange (Frozen mut) mut => Mutable mut+#endif+-- the type synonyms look nicer in the haddocks, otherwise it doesn't matter which one we use++#if __GLASGOW_HASKELL__ >= 704+type Immutable imm = PhaseChange imm (Thawed imm)+#else+class PhaseChange imm (Thawed imm) => Immutable imm+instance PhaseChange imm (Thawed imm) => Immutable imm+#endif++-- | Returns the input argument viewed as a mutable type. The input argument must not be used+-- afterwards.+unsafeThaw :: (Immutable imm, MonadST mST, s ~ World mST) => imm -> mST (Thawed imm s)+unsafeThaw = liftST . unsafeThawImpl+{-# INLINABLE unsafeThaw #-}+{-# SPECIALIZE unsafeThaw :: (Immutable imm, s ~ World (ST s)) => imm -> ST s (Thawed imm s) #-}+{-# SPECIALIZE unsafeThaw :: Immutable imm => imm -> IO (Thawed imm RealWorld) #-}+-- NOTE this is extremely delicate!+-- With IO it only works if I pre-expand the World type family, with ST it+-- only works if I don't. And if I use World directly in the original signature+-- instead of naming it 's', everything changes again.+-- In general the only way to figure it out seems to be trial and error.+-- Otherwise GHC says things like: "RULE left-hand side too complicated to desugar",+-- or sometimes "match_co baling out".++-- | Returns the input argument viewed as an immutable type. The input argument must not be used+-- afterwards.+unsafeFreeze :: (Mutable mut, MonadST mST, s ~ World mST) => mut s -> mST (Frozen mut)+unsafeFreeze = liftST . unsafeFreezeImpl+{-# INLINABLE unsafeFreeze #-}+{-# SPECIALIZE unsafeFreeze :: (Mutable mut, s ~ World (ST s)) => mut s -> ST s (Frozen mut) #-}+{-# SPECIALIZE unsafeFreeze :: (Mutable mut, s ~ RealWorld) => mut s -> IO (Frozen mut) #-}++-- | Make a copy of mutable data.+copy :: (Mutable mut, MonadST mST, s ~ World mST) => mut s -> mST (mut s)+copy = liftST . copyImpl+{-# INLINABLE copy #-}+{-# SPECIALIZE copy :: (Mutable mut, s ~ World (ST s)) => mut s -> ST s (mut s) #-}+{-# SPECIALIZE copy :: (Mutable mut, s ~ RealWorld) => mut s -> IO (mut s) #-}++-- | Get a copy of immutable data in mutable form.+thaw :: (Immutable imm, MonadST mST, s ~ World mST) => imm -> mST (Thawed imm s)+thaw = thawImpl+{-# INLINE thaw #-}++thawImpl :: (PhaseChange imm mut, MonadST mST) => imm -> mST (mut (World mST))+thawImpl = copy <=< unsafeThaw+{-# INLINABLE thawImpl #-}+{-# SPECIALIZE thawImpl :: PhaseChange imm mut => imm -> ST s (mut (World (ST s))) #-}+{-# SPECIALIZE thawImpl :: PhaseChange imm mut => imm -> IO (mut (World IO)) #-}+-- need to do this ugly thaw/thawImpl thing because I couldn't find any way at all to get+-- the SPECIALIZE to work otherwise+-- (interestingly unsafeThaw has the same exact type signature and didn't have problems...)++-- | Get a copy of mutable data in immutable form.+freeze :: (Mutable mut, MonadST mST, s ~ World mST) => mut s -> mST (Frozen mut)+freeze = unsafeFreeze <=< copy+{-# INLINABLE freeze #-}+{-# SPECIALIZE freeze :: (Mutable mut, s ~ World (ST s)) => mut s -> ST s (Frozen mut) #-}+{-# SPECIALIZE freeze :: (Mutable mut, s ~ RealWorld) => mut s -> IO (Frozen mut) #-}++-- | Produce immutable data from a mutating computation. No copies are made.+frozen :: Mutable mut => (forall s. ST s (mut s)) -> Frozen mut+frozen m = runST $ unsafeFreeze =<< m+{-# NOINLINE [1] frozen #-}+-- {-# INLINABLE frozen #-}+-- I don't see why these should conflict, but GHC says they do++-- | Make an update of immutable data by applying a mutating action. This function allows for+-- copy elision.+-- +-- Each chain of 'updateWith's makes only one copy. A chain of 'updateWith's on+-- top of a 'frozen' makes no copies.+updateWith :: Mutable mut => (forall s. mut s -> ST s ()) -> Frozen mut -> Frozen mut+updateWith f a = runST $ do { m <- thaw a; f m; unsafeFreeze m }+{-# NOINLINE [1] updateWith #-}+-- {-# INLINABLE updateWith #-}+-- really wanted to do this the other way around with Immutable and Thawed, but I found+-- absolutely no way to get the RULES to work that way, not even with the thaw/thawImpl trick++type Maker mut = forall s. ST s (mut s)+type Updater mut = forall s. mut s -> ST s ()++{-# RULES+ "updateWith/frozen"+ forall (stm :: Maker mut) (f :: Updater mut).+ updateWith f (frozen stm) = frozen (stm >>= \m -> f m >> return m);++ "updateWith/updateWith"+ forall (f :: Updater mut) (g :: Updater mut) i.+ updateWith f (updateWith g i) = updateWith (\m -> f m >> g m) i+ #-}++updateWithResult :: Immutable imm => (forall s. Thawed imm s -> ST s a) -> imm -> (imm, a)+updateWithResult f a = runST $ do { m <- thaw a; r <- f m; i <- unsafeFreeze m; return (i, r) }+{-# INLINABLE updateWithResult #-}++{- RULES+ "updateWithResult/frozen"+ forall (m :: Mutable mut => (forall s. ST s (mut s))) (f :: Immutable imm => (forall s. Thawed imm s -> ST s a)).+ updateWithResult f (frozen m) = frozen (m >>= \m' -> f m' >> return m');+ -}++--updateManyWith :: (Immutable imm, Functor f) => (forall s. f (Thawed imm s) -> ST s ()) -> f imm -> f imm+--updateManyWith f a = runST $ do { ++--withPlus :: Immutable a => a -> (forall s. Thawed a s -> ST s (Thawed a s, b)) -> (a, b)++{-+let (foo, vec') = updateWithResult asdf vec+ (bar, vec'') = updateWithResult bsdf vec'+ (baz, vec''') = updateWithResult csdf vec''+-}++-- | Read a value from immutable data with a reading-computation on mutable data.+-- This function is referentially transparent as long as the computation does+-- not mutate its input argument, but there is no way to enforce this.+readWith :: Immutable imm => (forall s. Thawed imm s -> ST s a) -> imm -> a+readWith f i = runST $ do { m <- unsafeThaw i; r <- f m; _ <- unsafeFreeze m; return r }++-- | Newtype for mutable types whose state thread parameter is in the second-to-last position+newtype M1 mut a s = M1 { unM1 :: mut s a }++--instance Newtype (M1 mut a s) (mut s a) where+-- pack = M1+-- unpack = unM1++unsafeThaw1 :: (PhaseChange (imm a) (M1 mut a), MonadST mST, s ~ World mST) => imm a -> mST (mut s a)+unsafeThaw1 = liftM unM1 . unsafeThaw+{-# INLINE unsafeThaw1 #-}++unsafeFreeze1 :: (PhaseChange (imm a) (M1 mut a), MonadST mST, s ~ World mST) => mut s a -> mST (imm a)+unsafeFreeze1 = unsafeFreeze . M1+{-# INLINE unsafeFreeze1 #-}++copy1 :: (PhaseChange (imm a) (M1 mut a), MonadST mST, s ~ World mST) => mut s a -> mST (mut s a)+copy1 = liftM unM1 . copy . M1+{-# INLINE copy1 #-}++thaw1 :: (PhaseChange (imm a) (M1 mut a), MonadST mST, s ~ World mST) => imm a -> mST (mut s a)+thaw1 = liftM unM1 . thaw+{-# INLINE thaw1 #-}++freeze1 :: (PhaseChange (imm a) (M1 mut a), MonadST mST, s ~ World mST) => mut s a -> mST (imm a)+freeze1 = freeze . M1+{-# INLINE freeze1 #-}++frozen1 :: PhaseChange (imm a) (M1 mut a) => (forall s. ST s (mut s a)) -> imm a+frozen1 m = frozen (liftM M1 m)+{-# INLINE frozen1 #-}++updateWith1 :: PhaseChange (imm a) (M1 mut a) => (forall s. mut s a -> ST s ()) -> imm a -> imm a+updateWith1 f = updateWith (f . unM1)+{-# INLINE updateWith1 #-}++readWith1 :: PhaseChange (imm a) (M1 mut a) => (forall s. mut s a -> ST s b) -> imm a -> b+readWith1 f = readWith (f . unM1)+{-# INLINE readWith1 #-}++-- | Newtype for mutable types whose state thread parameter is in the third-to-last position+newtype M2 mut a b s = M2 { unM2 :: mut s a b }++--instance Newtype (M2 mut a b s) (mut s a b) where+-- pack = M2+-- unpack = unM2++unsafeThaw2 :: (PhaseChange (imm a b) (M2 mut a b), MonadST mST, s ~ World mST) => imm a b -> mST (mut s a b)+unsafeThaw2 = liftM unM2 . unsafeThaw+{-# INLINE unsafeThaw2 #-}++unsafeFreeze2 :: (PhaseChange (imm a b) (M2 mut a b), MonadST mST, s ~ World mST) => mut s a b -> mST (imm a b)+unsafeFreeze2 = unsafeFreeze . M2+{-# INLINE unsafeFreeze2 #-}++copy2 :: (PhaseChange (imm a b) (M2 mut a b), MonadST mST, s ~ World mST) => mut s a b -> mST (mut s a b)+copy2 = liftM unM2 . copy . M2+{-# INLINE copy2 #-}++thaw2 :: (PhaseChange (imm a b) (M2 mut a b), MonadST mST, s ~ World mST) => imm a b -> mST (mut s a b)+thaw2 = liftM unM2 . thaw+{-# INLINE thaw2 #-}++freeze2 :: (PhaseChange (imm a b) (M2 mut a b), MonadST mST, s ~ World mST) => mut s a b -> mST (imm a b)+freeze2 = freeze . M2+{-# INLINE freeze2 #-}++frozen2 :: PhaseChange (imm a b) (M2 mut a b) => (forall s. ST s (mut s a b)) -> imm a b+frozen2 m = frozen (liftM M2 m)+{-# INLINE frozen2 #-}++updateWith2 :: PhaseChange (imm a b) (M2 mut a b) => (forall s. mut s a b -> ST s ()) -> imm a b -> imm a b+updateWith2 f = updateWith (f . unM2)+{-# INLINE updateWith2 #-}++readWith2 :: PhaseChange (imm a b) (M2 mut a b) => (forall s. mut s a b -> ST s c) -> imm a b -> c+readWith2 f = readWith (f . unM2)+{-# INLINE readWith2 #-}
+ Data/PhaseChange/Unsafe.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE CPP #-}++#if __GLASGOW_HASKELL__ >= 704+{-# LANGUAGE Unsafe #-}+#endif++-- | This module provides functions on PhaseChangeable data which can break referential transparency if used incorrectly.+-- For safe functions, see "Data.PhaseChange". To write an instance, see "Data.PhaseChange.Impl".+module Data.PhaseChange.Unsafe+ (+-- * Unsafe functions+ unsafeThaw, unsafeFreeze, readWith,+-- * Convenience functions for working with @'M1'@+ unsafeThaw1, unsafeFreeze1, readWith1,+-- * Convenience functions for working with @'M2'@+ unsafeThaw2, unsafeFreeze2, readWith2+ )+ where++import Data.PhaseChange.Internal+import Data.PhaseChange.Instances ()
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright 2012 Gábor Lehel++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ phasechange.cabal view
@@ -0,0 +1,79 @@+name: phasechange+category: Data+version: 0.1+author: Gábor Lehel+maintainer: Gábor Lehel <illissius@gmail.com>+homepage: http://github.com/glehel/phasechange+copyright: Copyright (C) 2012 Gábor Lehel+license: BSD3+license-file: LICENSE+stability: experimental+cabal-version: >= 1.10+build-type: Simple+synopsis: Freezing, thawing, and copy elision+description: + This library provides a class for types which present the same underlying data in both an immutable (frozen) as well as a mutable (thawed) form,+ and various functions to manipulate them. Some of the functions allow for copy elision.+ .+ Instances are provided for the array types from the @primitive@, @array@, and @vector@ packages, but this is mainly for completeness: there is+ nothing these instances do which @vector@ doesn't already do better. The main purpose, rather, is to assist new types, for instance types whose implementation relies on destructive-update foreign imports, and cases when writing a full stream fusion framework isn't practical.+ .+ There are three modules:+ .+ [Data.PhaseChange] This module exports the class without its methods, together with functions which guarantee referential transparency+ (provided that instances are well-behaved). This is the module you should normally import to work with PhaseChangeable data.+ .+ [Data.PhaseChange.Unsafe] This module exports functions which can break referential transparency if they are used improperly. Be careful.+ .+ [Data.PhaseChange.Impl] This module exports the class along with its methods. Import it if you want to define a new instance.++source-repository head+ type: git+ location: git://github.com/glehel/phasechange.git++library+ default-language:+ Haskell98++ other-extensions:+ CPP,+ MagicHash,+ Rank2Types,+ TypeFamilies,+ UnboxedTuples,+ FlexibleContexts,+ FlexibleInstances,+ UndecidableInstances,+ MultiParamTypeClasses++ impl(ghc >= 7.4):+ other-extensions:+ Trustworthy,+ ConstraintKinds++ impl(ghc >= 7.6):+ other-extensions:+ Unsafe++ build-depends:+ base >= 4.4 && < 4.6,+ ghc-prim,+ primitive == 0.4.*,+-- newtype == 0.2.*,+ monad-st == 0.2.*,+ array == 0.4.*,+ vector == 0.9.*++ exposed-modules:+ Data.PhaseChange+ Data.PhaseChange.Unsafe+ Data.PhaseChange.Impl++ other-modules:+ Data.PhaseChange.Internal+ Data.PhaseChange.Instances++ include-dirs: .++ ghc-options:+ -Wall