packages feed

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 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