diff --git a/Data/PhaseChange.hs b/Data/PhaseChange.hs
new file mode 100644
--- /dev/null
+++ b/Data/PhaseChange.hs
@@ -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 ()
diff --git a/Data/PhaseChange/Impl.hs b/Data/PhaseChange/Impl.hs
new file mode 100644
--- /dev/null
+++ b/Data/PhaseChange/Impl.hs
@@ -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 ()
diff --git a/Data/PhaseChange/Instances.hs b/Data/PhaseChange/Instances.hs
new file mode 100644
--- /dev/null
+++ b/Data/PhaseChange/Instances.hs
@@ -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
+
diff --git a/Data/PhaseChange/Internal.hs b/Data/PhaseChange/Internal.hs
new file mode 100644
--- /dev/null
+++ b/Data/PhaseChange/Internal.hs
@@ -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 #-}
diff --git a/Data/PhaseChange/Unsafe.hs b/Data/PhaseChange/Unsafe.hs
new file mode 100644
--- /dev/null
+++ b/Data/PhaseChange/Unsafe.hs
@@ -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 ()
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/phasechange.cabal b/phasechange.cabal
new file mode 100644
--- /dev/null
+++ b/phasechange.cabal
@@ -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
