-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Automatic piecewise-mutable references for your types -- -- Associate and generate "piecewise-mutable" versions for your composite -- data types. Think of it like a "generalized MVector for all ADTs". -- -- Useful for a situation where you have a record with many fields (or -- many nested records) that you want to use for efficient mutable -- in-place algorithms. This library lets you do efficient "piecewise" -- mutations (operations that only edit one field), and also efficient -- entire-datatype copies/updates, as well, in many cases. -- -- See https://mutable.jle.im for official introduction and -- documentation, or jump right in by importing Data.Mutable. @package mutable @version 0.1.0.1 -- | Provides Ref instances for various data types, as well as -- automatic derivation of instances. See Data.Mutable for more -- information. module Data.Mutable.Instances -- | Ref for components in a vinyl Rec. newtype RecRef m f a RecRef :: Ref m (f a) -> RecRef m f a [getRecRef] :: RecRef m f a -> Ref m (f a) -- | The mutable reference of the HList type from generic-lens. data HListRef :: (Type -> Type) -> [Type] -> Type [NilRef] :: HListRef m '[] [:!>] :: Ref m a -> HListRef m as -> HListRef m (a : as) infixr 5 :!> -- | Automatically generate a piecewise mutable reference for any -- Generic instance. -- --
-- -- | any Generic instance
-- data MyType = MyType { mtInt :: Int, mtDouble :: Double }
-- deriving (Generic, Show)
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- -- ghci> r <- thawRef (MyType 3 4.5) -- ghci> freezeRef r -- MyType 3 4.5 -- ghci> freezePart (fieldMut #mtInt) r -- 3 -- ghci> copyPart (fieldMut #mtDouble) 1.23 -- ghci> freezeRef r -- MyType 3 1.23 ---- -- Note that this is basically just a bunch of tupled refs for a product -- type. For a sum type (with multiple constructors), an extra layer of -- indirection is added to account for the dynamically changable shape. -- -- See Data.Mutable.Parts and Data.Mutable.Branches for -- nice ways to inspect and mutate the internals of this type (as -- demonstrated above). -- -- If the facilities in those modules are not adequate, you can also -- manually crack open GRef and work with the internals. Getting -- the type of unGRef @MyType should allow you to -- navigate what is going on, if you are familiar with -- GHC.Generics. However, ideally, you would never need to do -- this. newtype GRef m a GRef :: GRef_ m (Rep a) () -> GRef m a [unGRef] :: GRef m a -> GRef_ m (Rep a) () -- | Default thawRef for GRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with GRef as the -- Ref. However, it can be useful if you are using a -- GRef m a just as a normal data type, independent of -- the Ref class. See documentation for GRef for more -- information. gThawRef :: (Generic a, GMutable m (Rep a)) => a -> m (GRef m a) -- | Default freezeRef for GRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with GRef as the -- Ref. However, it can be useful if you are using a -- GRef m a just as a normal data type, independent of -- the Ref class. See documentation for GRef for more -- information. gFreezeRef :: (Generic a, GMutable m (Rep a)) => GRef m a -> m a -- | Default copyRef for GRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with GRef as the -- Ref. However, it can be useful if you are using a -- GRef m a just as a normal data type, independent of -- the Ref class. See documentation for GRef for more -- information. gCopyRef :: (Generic a, GMutable m (Rep a)) => GRef m a -> a -> m () -- | Default moveRef for GRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with GRef as the -- Ref. However, it can be useful if you are using a -- GRef m a just as a normal data type, independent of -- the Ref class. See documentation for GRef for more -- information. gMoveRef :: GMutable m (Rep a) => GRef m a -> GRef m a -> m () -- | Default cloneRef for GRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with GRef as the -- Ref. However, it can be useful if you are using a -- GRef m a just as a normal data type, independent of -- the Ref class. See documentation for GRef for more -- information. gCloneRef :: GMutable m (Rep a) => GRef m a -> m (GRef m a) -- | Default unsafeThawRef for GRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with GRef as the -- Ref. However, it can be useful if you are using a -- GRef m a just as a normal data type, independent of -- the Ref class. See documentation for GRef for more -- information. gUnsafeThawRef :: (Generic a, GMutable m (Rep a)) => a -> m (GRef m a) -- | Default unsafeFreezeRef for GRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with GRef as the -- Ref. However, it can be useful if you are using a -- GRef m a just as a normal data type, independent of -- the Ref class. See documentation for GRef for more -- information. gUnsafeFreezeRef :: (Generic a, GMutable m (Rep a)) => GRef m a -> m a -- | Class for automatic generation of Ref for Generic -- instances. See GRef for more information. class Monad m => GMutable m f where { type family GRef_ m f = (u :: k -> Type) | u -> f; } -- | Default thawRef for the higher-kinded data pattern, a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with z -- (RefFor m) as the Ref. However, it can be useful if -- you are using a z (RefFor m) just as a normal data -- type, independent of the Ref class. See documentation for -- Mutable for more information. thawHKD :: forall z m. (Generic (z Identity), Generic (z (RefFor m)), GMutable m (Rep (z Identity)), GRef_ m (Rep (z Identity)) ~ Rep (z (RefFor m))) => z Identity -> m (z (RefFor m)) -- | Default freezeRef for the higher-kinded data pattern, a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with z -- (RefFor m) as the Ref. However, it can be useful if -- you are using a z (RefFor m) just as a normal data -- type, independent of the Ref class. See documentation for -- Mutable for more information. freezeHKD :: forall z m. (Generic (z Identity), Generic (z (RefFor m)), GMutable m (Rep (z Identity)), GRef_ m (Rep (z Identity)) ~ Rep (z (RefFor m))) => z (RefFor m) -> m (z Identity) -- | Default copyRef for the higher-kinded data pattern, a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with z -- (RefFor m) as the Ref. However, it can be useful if -- you are using a z (RefFor m) just as a normal data -- type, independent of the Ref class. See documentation for -- Mutable for more information. copyHKD :: forall z m. (Generic (z Identity), Generic (z (RefFor m)), GMutable m (Rep (z Identity)), GRef_ m (Rep (z Identity)) ~ Rep (z (RefFor m))) => z (RefFor m) -> z Identity -> m () -- | Default moveRef for the higher-kinded data pattern, a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with z -- (RefFor m) as the Ref. However, it can be useful if -- you are using a z (RefFor m) just as a normal data -- type, independent of the Ref class. See documentation for -- Mutable for more information. moveHKD :: forall z m. (Generic (z (RefFor m)), GMutable m (Rep (z Identity)), GRef_ m (Rep (z Identity)) ~ Rep (z (RefFor m))) => z (RefFor m) -> z (RefFor m) -> m () -- | Default cloneRef for the higher-kinded data pattern, a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with z -- (RefFor m) as the Ref. However, it can be useful if -- you are using a z (RefFor m) just as a normal data -- type, independent of the Ref class. See documentation for -- Mutable for more information. cloneHKD :: forall z m. (Generic (z (RefFor m)), GMutable m (Rep (z Identity)), GRef_ m (Rep (z Identity)) ~ Rep (z (RefFor m))) => z (RefFor m) -> m (z (RefFor m)) -- | Default unsafeThawRef for the higher-kinded data pattern, a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with z -- (RefFor m) as the Ref. However, it can be useful if -- you are using a z (RefFor m) just as a normal data -- type, independent of the Ref class. See documentation for -- Mutable for more information. unsafeThawHKD :: forall z m. (Generic (z Identity), Generic (z (RefFor m)), GMutable m (Rep (z Identity)), GRef_ m (Rep (z Identity)) ~ Rep (z (RefFor m))) => z Identity -> m (z (RefFor m)) -- | Default unsafeFreezeRef for the higher-kinded data pattern, a -- la https://reasonablypolymorphic.com/blog/higher-kinded-data/. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with z -- (RefFor m) as the Ref. However, it can be useful if -- you are using a z (RefFor m) just as a normal data -- type, independent of the Ref class. See documentation for -- Mutable for more information. unsafeFreezeHKD :: forall z m. (Generic (z Identity), Generic (z (RefFor m)), GMutable m (Rep (z Identity)), GRef_ m (Rep (z Identity)) ~ Rep (z (RefFor m))) => z (RefFor m) -> m (z Identity) -- | A Ref that works by using the Mutable instance of an -- equivalent type. This is useful for newtype wrappers, so you can use -- the underlying data type's Mutable instance. -- --
-- newtype MyVec = MyVec (Vector Double) -- -- instance Mutable m MyVec where -- type Ref m MyVec = CoerceRef m s (Vector Double) ---- -- The Ref m MyVec uses the a MVector Double -- under the hood. -- -- It's essentially a special case of GRef for newtypes. newtype CoerceRef m s a CoerceRef :: Ref m a -> CoerceRef m s a [getCoerceRef] :: CoerceRef m s a -> Ref m a -- | Default thawRef for CoerceRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with CoerceRef -- as the Ref. However, it can be useful if you are using a -- CoerceRef m s a just as a normal data type, -- independent of the Ref class. See documentation for -- CoerceRef for more information. thawCoerce :: (Coercible s a, Mutable m a) => s -> m (CoerceRef m s a) -- | Default freezeRef for CoerceRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with CoerceRef -- as the Ref. However, it can be useful if you are using a -- CoerceRef m s a just as a normal data type, -- independent of the Ref class. See documentation for -- CoerceRef for more information. freezeCoerce :: (Coercible s a, Mutable m a) => CoerceRef m s a -> m s -- | Default copyRef for CoerceRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with CoerceRef -- as the Ref. However, it can be useful if you are using a -- CoerceRef m s a just as a normal data type, -- independent of the Ref class. See documentation for -- CoerceRef for more information. copyCoerce :: (Coercible s a, Mutable m a) => CoerceRef m s a -> s -> m () -- | Default moveRef for CoerceRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with CoerceRef -- as the Ref. However, it can be useful if you are using a -- CoerceRef m s a just as a normal data type, -- independent of the Ref class. See documentation for -- CoerceRef for more information. moveCoerce :: Mutable m a => CoerceRef m s a -> CoerceRef m s a -> m () -- | Default cloneRef for CoerceRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with CoerceRef -- as the Ref. However, it can be useful if you are using a -- CoerceRef m s a just as a normal data type, -- independent of the Ref class. See documentation for -- CoerceRef for more information. cloneCoerce :: Mutable m a => CoerceRef m s a -> m (CoerceRef m s a) -- | Default unsafeThawRef for CoerceRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with CoerceRef -- as the Ref. However, it can be useful if you are using a -- CoerceRef m s a just as a normal data type, -- independent of the Ref class. See documentation for -- CoerceRef for more information. unsafeThawCoerce :: (Coercible s a, Mutable m a) => s -> m (CoerceRef m s a) -- | Default unsafeFreezeRef for CoerceRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with CoerceRef -- as the Ref. However, it can be useful if you are using a -- CoerceRef m s a just as a normal data type, -- independent of the Ref class. See documentation for -- CoerceRef for more information. unsafeFreezeCoerce :: (Coercible s a, Mutable m a) => CoerceRef m s a -> m s -- | A Ref that works for any instance of Traversable, by -- using the fields of the Traversable instance to purely -- store mutable references. -- -- Note that this really only makes complete sense if the -- Traversable is fixed-size, or you never modify the length of -- the traversable as you use it as a reference. -- -- If you do modify the length, copying and modifying semantics -- can be a bit funky: -- --
-- ghci> r <- thawTraverse [1..10] -- ghci> copyTraverse r [0,0,0,0] -- ghci> freezeTraverse r -- [0,0,0,0,5,6,7,8,9,10] -- ghci> copyTraverse r [20..50] -- ghci> freezeTraverse r -- [20,21,22,23,24,25,26,27,28,29] --newtype TraverseRef m f a TraverseRef :: f (Ref m a) -> TraverseRef m f a [getTraverseRef] :: TraverseRef m f a -> f (Ref m a) -- | Default thawRef for TraverseRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with TraverseRef -- as the Ref. However, it can be useful if you are using a -- TraverseRef m f a just as a normal data type, -- independent of the Ref class. See documentation for -- TraverseRef for more information. thawTraverse :: (Traversable f, Mutable m a) => f a -> m (TraverseRef m f a) -- | Default freezeRef for TraverseRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with TraverseRef -- as the Ref. However, it can be useful if you are using a -- TraverseRef m f a just as a normal data type, -- independent of the Ref class. See documentation for -- TraverseRef for more information. freezeTraverse :: (Traversable f, Mutable m a) => TraverseRef m f a -> m (f a) -- | Default copyRef for TraverseRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with TraverseRef -- as the Ref. However, it can be useful if you are using a -- TraverseRef m f a just as a normal data type, -- independent of the Ref class. See documentation for -- TraverseRef for more information. copyTraverse :: (Traversable f, Mutable m a) => TraverseRef m f a -> f a -> m () -- | Default moveRef for TraverseRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with TraverseRef -- as the Ref. However, it can be useful if you are using a -- TraverseRef m f a just as a normal data type, -- independent of the Ref class. See documentation for -- TraverseRef for more information. moveTraverse :: (Traversable f, Mutable m a) => TraverseRef m f a -> TraverseRef m f a -> m () -- | Default cloneRef for TraverseRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with TraverseRef -- as the Ref. However, it can be useful if you are using a -- TraverseRef m f a just as a normal data type, -- independent of the Ref class. See documentation for -- TraverseRef for more information. cloneTraverse :: (Traversable f, Mutable m a) => TraverseRef m f a -> m (TraverseRef m f a) -- | Default unsafeThawRef for TraverseRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with TraverseRef -- as the Ref. However, it can be useful if you are using a -- TraverseRef m f a just as a normal data type, -- independent of the Ref class. See documentation for -- TraverseRef for more information. unsafeThawTraverse :: (Traversable f, Mutable m a) => f a -> m (TraverseRef m f a) -- | Default unsafeFreezeRef for TraverseRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with TraverseRef -- as the Ref. However, it can be useful if you are using a -- TraverseRef m f a just as a normal data type, -- independent of the Ref class. See documentation for -- TraverseRef for more information. unsafeFreezeTraverse :: (Traversable f, Mutable m a) => TraverseRef m f a -> m (f a) -- | A "Ref" that can be used to give a default Mutable -- instance that is immutable. Nothing is allocated ever, all attempts to -- modify it will be ignored, and freezeRef will just get the -- original thawed value. -- -- Really only exists to be used with Immutable. newtype ImmutableRef a ImmutableRef :: a -> ImmutableRef a [getImmutableRef] :: ImmutableRef a -> a -- | Default thawRef for ImmutableRef. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with -- ImmutableRef as the Ref. However, it can be useful if -- you are using a ImmutableRef m s a just as a normal -- data type, independent of the Ref class. See documentation for -- ImmutableRef for more information. thawImmutable :: Applicative m => a -> m (ImmutableRef a) -- | Default freezeRef for ImmutableRef. This will always -- return the originally thawed value, ignoring all copies and writes. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with -- ImmutableRef as the Ref. However, it can be useful if -- you are using a ImmutableRef m s a just as a normal -- data type, independent of the Ref class. See documentation for -- ImmutableRef for more information. freezeImmutable :: Applicative m => ImmutableRef a -> m a -- | Default copyRef for ImmutableRef. This is a no-op and -- does nothing, since freezing will always return the originally thawed -- value. -- -- You likely won't ever use this directly, since it is automatically -- provided if you have a Mutable instance with -- ImmutableRef as the Ref. However, it can be useful if -- you are using a ImmutableRef m s a just as a normal -- data type, independent of the Ref class. See documentation for -- ImmutableRef for more information. copyImmutable :: Applicative m => ImmutableRef a -> a -> m () -- | A Ref for instances of GMutable, which are the -- GHC.Generics combinators. newtype GMutableRef m f a GMutableRef :: GRef_ m f a -> GMutableRef m f a [getGMutableRef] :: GMutableRef m f a -> GRef_ m f a -- | Wraps :+: in a mutable reference. Used internally to represent -- generic sum references. newtype MutSumF m f g a MutSumF :: MutVar (PrimState m) ((f :+: g) a) -> MutSumF m f g a [getMutSumF] :: MutSumF m f g a -> MutVar (PrimState m) ((f :+: g) a) -- | Useful type family to Ref m over every item in a -- type-level list -- --
-- ghci> :kind! MapRef IO '[Int, V.Vector Double] -- '[ MutVar RealWorld Int, MVector RealWorld Double ] --type family MapRef m as instance forall k (m :: * -> *) (f :: k -> *) (a :: k). GHC.Classes.Eq (Data.Mutable.Internal.Ref m (f a)) => GHC.Classes.Eq (Data.Mutable.Instances.RecRef m f a) instance forall k (m :: * -> *) (f :: k -> *) (a :: k). GHC.Classes.Ord (Data.Mutable.Internal.Ref m (f a)) => GHC.Classes.Ord (Data.Mutable.Instances.RecRef m f a) instance GHC.Base.Monad m => Data.Mutable.Internal.Mutable m (Data.Generics.Product.Internal.HList.HList '[]) instance (GHC.Base.Monad m, Data.Mutable.Internal.Mutable m a, Data.Mutable.Internal.Mutable m (Data.Generics.Product.Internal.HList.HList as), Data.Mutable.Internal.Ref m (Data.Generics.Product.Internal.HList.HList as) GHC.Types.~ Data.Mutable.Instances.HListRef m as) => Data.Mutable.Internal.Mutable m (Data.Generics.Product.Internal.HList.HList (a : as)) instance forall u (m :: * -> *) (f :: u -> *). GHC.Base.Monad m => Data.Mutable.Internal.Mutable m (Data.Vinyl.Core.Rec f '[]) instance forall a1 (m :: * -> *) (f :: a1 -> *) (a2 :: a1) (as :: [a1]). (GHC.Base.Monad m, Data.Mutable.Internal.Mutable m (f a2), Data.Mutable.Internal.Mutable m (Data.Vinyl.Core.Rec f as), Data.Mutable.Internal.Ref m (Data.Vinyl.Core.Rec f as) GHC.Types.~ Data.Vinyl.Core.Rec (Data.Mutable.Instances.RecRef m f) as) => Data.Mutable.Internal.Mutable m (Data.Vinyl.Core.Rec f (a2 : as)) instance forall k (m :: * -> *) (as :: [k]) (f :: k -> *). (GHC.Base.Monad m, Data.Vinyl.Core.RecApplicative as, Data.Vinyl.TypeLevel.NatToInt (Data.Vinyl.TypeLevel.RLength as), Data.Vinyl.Core.RPureConstrained (Data.Vinyl.ARec.IndexableField as) as, Data.Mutable.Internal.Mutable m (Data.Vinyl.Core.Rec f as), Data.Mutable.Internal.Ref m (Data.Vinyl.Core.Rec f as) GHC.Types.~ Data.Vinyl.Core.Rec (Data.Mutable.Instances.RecRef m f) as) => Data.Mutable.Internal.Mutable m (Data.Vinyl.ARec.ARec f as) instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Types.Int instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Integer.Type.Integer instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Natural.Natural instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m (GHC.Real.Ratio a) instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Types.Float instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Types.Double instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m (Data.Complex.Complex a) instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Types.Bool instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Types.Char instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Types.Word instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Word.Word8 instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Word.Word16 instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m GHC.Word.Word64 instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CChar instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CSChar instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CUChar instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CShort instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CUShort instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CInt instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CUInt instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CLong instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CULong instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CPtrdiff instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CSize instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CWchar instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CSigAtomic instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CLLong instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CULLong instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CBool instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CIntPtr instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CUIntPtr instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CIntMax instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CUIntMax instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CClock instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CTime instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CUSeconds instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CSUSeconds instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CFloat instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Foreign.C.Types.CDouble instance Data.Mutable.Internal.Mutable m a => Data.Mutable.Internal.Mutable m (Data.Functor.Identity.Identity a) instance forall k (m :: * -> *) a (b :: k). Data.Mutable.Internal.Mutable m a => Data.Mutable.Internal.Mutable m (Data.Functor.Const.Const a b) instance forall k (m :: * -> *) a (b :: k). Data.Mutable.Internal.Mutable m a => Data.Mutable.Internal.Mutable m (Data.Vinyl.Functor.Const a b) instance Data.Mutable.Internal.Mutable m a => Data.Mutable.Internal.Mutable m (Data.Semigroup.Internal.Product a) instance Data.Mutable.Internal.Mutable m a => Data.Mutable.Internal.Mutable m (Data.Semigroup.Internal.Sum a) instance Data.Mutable.Internal.Mutable m a => Data.Mutable.Internal.Mutable m (Data.Ord.Down a) instance Data.Mutable.Internal.Mutable m a => Data.Mutable.Internal.Mutable m (Data.Semigroup.Internal.Dual a) instance (Data.Mutable.Internal.Mutable m a, Control.Monad.Primitive.PrimMonad m) => Data.Mutable.Internal.Mutable m (GHC.Maybe.Maybe a) instance (Data.Mutable.Internal.Mutable m a, Data.Mutable.Internal.Mutable m b, Control.Monad.Primitive.PrimMonad m) => Data.Mutable.Internal.Mutable m (Data.Either.Either a b) instance forall k (m :: * -> *) (f :: k -> *) (a :: k) (g :: k -> *). (Data.Mutable.Internal.Mutable m (f a), Data.Mutable.Internal.Mutable m (g a)) => Data.Mutable.Internal.Mutable m (Data.Functor.Product.Product f g a) instance forall k (m :: * -> *) (f :: k -> *) (a :: k) (g :: k -> *). (Data.Mutable.Internal.Mutable m (f a), Data.Mutable.Internal.Mutable m (g a), Control.Monad.Primitive.PrimMonad m) => Data.Mutable.Internal.Mutable m (Data.Functor.Sum.Sum f g a) instance forall k k1 (m :: * -> *) (f :: k -> *) (g :: k1 -> k) (a :: k1). Data.Mutable.Internal.Mutable m (f (g a)) => Data.Mutable.Internal.Mutable m (Data.Functor.Compose.Compose f g a) instance (Control.Monad.Primitive.PrimMonad m, Data.Mutable.Internal.Mutable m a) => Data.Mutable.Internal.Mutable m [a] instance Data.Mutable.Internal.Mutable m a => Data.Mutable.Internal.Mutable m (Data.Vinyl.Functor.Identity a) instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m (Data.Vector.Vector a) instance (Control.Monad.Primitive.PrimMonad m, Foreign.Storable.Storable a) => Data.Mutable.Internal.Mutable m (Data.Vector.Storable.Vector a) instance (Control.Monad.Primitive.PrimMonad m, Data.Vector.Unboxed.Base.Unbox a) => Data.Mutable.Internal.Mutable m (Data.Vector.Unboxed.Base.Vector a) instance (Control.Monad.Primitive.PrimMonad m, Data.Primitive.Types.Prim a) => Data.Mutable.Internal.Mutable m (Data.Vector.Primitive.Vector a) instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m (Data.Primitive.Array.Array a) instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m (Data.Primitive.SmallArray.SmallArray a) instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m Data.Primitive.ByteArray.ByteArray instance (Control.Monad.Primitive.PrimMonad m, Data.Primitive.Types.Prim a) => Data.Mutable.Internal.Mutable m (Data.Primitive.PrimArray.PrimArray a) instance GHC.Base.Monad m => Data.Mutable.Internal.Mutable m Data.Void.Void instance GHC.Base.Monad m => Data.Mutable.Internal.Mutable m () instance (GHC.Base.Monad m, Data.Mutable.Internal.Mutable m a, Data.Mutable.Internal.Mutable m b) => Data.Mutable.Internal.Mutable m (a, b) instance (GHC.Base.Monad m, Data.Mutable.Internal.Mutable m a, Data.Mutable.Internal.Mutable m b, Data.Mutable.Internal.Mutable m c) => Data.Mutable.Internal.Mutable m (a, b, c) instance (GHC.Base.Monad m, Data.Mutable.Internal.Mutable m a, Data.Mutable.Internal.Mutable m b, Data.Mutable.Internal.Mutable m c, Data.Mutable.Internal.Mutable m d) => Data.Mutable.Internal.Mutable m (a, b, c, d) instance (GHC.Base.Monad m, Data.Mutable.Internal.Mutable m a, Data.Mutable.Internal.Mutable m b, Data.Mutable.Internal.Mutable m c, Data.Mutable.Internal.Mutable m d, Data.Mutable.Internal.Mutable m e) => Data.Mutable.Internal.Mutable m (a, b, c, d, e) -- | Provides the Mutable typeclass and various helpers. See -- Mutable for the main "entrypoint". module Data.Mutable.Class -- | An instance of Mutable m a means that a can -- be stored a mutable reference in monad m. -- -- The associated type Ref m a links any a to -- the type of its canonical mutable version. -- -- The benefit of this typeclass, instead of just using -- IORef or MutVar or specific mutable versions like -- Vector and MVector, is two-fold: -- --
instance (Mutable m a, Mutable m b) => -- Mutable m (a, b)If a and b are -- piecwise-mutable, then the instance here will appropriately utilize -- that fact.
-- data TwoVectors = TV
-- { tvInt :: Vector Int
-- , tvDouble :: Vector Double
-- }
-- deriving Generic
--
-- instance Mutable m TwoVectors where
-- type Ref m TwoVectors = GRef m TwoVectors
--
--
-- Then now we get:
--
-- -- thawRef :: TwoVectors -> m (GRef m TwoVectors) -- freezeRef :: GRef m TwoVectors -> m TwoVectors ---- -- And GRef m TwoVectors is now a piecewise-mutable -- reference storing each part in a way that can be modified separately -- (for example, with tools from Data.Mutable.Parts). It does this -- by internally allocating two MVectors. If the two vectors are -- large, this can be much more efficient to modify (if you are modifying -- several times) than by just doing alterations on -- TwoVectors. It is also much better for large vectors if you -- plan on modifying only a single item in the vector. -- -- If you are using the "higher-kinded" data pattern, a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/, -- then we can also do: -- --
-- data TwoVectors f = TV
-- { tvInt :: HKD f (Vector Int)
-- , tvDouble :: HKD f (Vector Double)
-- }
-- deriving Generic
--
-- instance Mutable (TwoVectors Identity) where
-- type Ref (TwoVectors Identity) = TwoVectors (RefFor m)
--
--
-- And now your mutable ref is literally going to be a product of the
-- components
--
-- -- ghci> tvr@(TV is ds) <- thawRef (TV xs ys) -- ghci> :t tvr -- TV (RefFor IO) -- ghci> :t is -- MVector RealWorld Int -- ghci> :t ds -- MVector RealWorld Double ---- -- So thawRef will actually just get you the same record type but -- with the mutable versions of each field. If you modify the mutable -- fields, and then later freezeRef the whole thing, the resulting -- frozen value will incorporate all of the changes to the individual -- fields. -- -- In addition, there are a few more "automatically derived" instances -- you can get by picking Ref: -- --
-- -- Make a mutable version for any newtype wrapper, using the Mutable -- -- of the underlying type -- newtype MyType = MT (Vector Double) -- -- type Ref m MyType = CoerceRef m MyType (Vector Double) -- -- -- Make a mutable version of any container, where the items are all -- -- mutable references. -- data MyContainer a = MC a a a a -- deriving (Functor, Foldable, Traversable) -- -- type Ref m (MyContainer a) = TraverseRef m MyContainer a ---- -- See https://mutable.jle.im/02-mutable-and-ref.html for more -- information on this typeclass and how to define instances -- automatically, and also -- --
-- type Ref m (Vector a) = MVector (PrimState m) a
--
--
-- This means that using thawRef on a Vector will give you
-- an MVector, using freezeRef on a Vector will give
-- you a Vector, etc.
--
--
-- thawRef
-- :: (PrimMonad m, s ~ PrimState m)
-- => Vector a
-- -> m (Vector s a)
--
-- freezeRef
-- :: (PrimMonad m, s ~ PrimState m)
-- => Vector s a
-- -> m (Vector a)
--
-- copyRef
-- :: (PrimMonad m, s ~ PrimState m)
-- => Vector s a
-- -> Vector a
-- -> m ()
--
--
-- This associated type must be unique for a, so no two types
-- a can have the same Ref m a. This makes type
-- inference a lot more useful: if you use freezeRef on an
-- MVector, for instance, the return type will be inferred to be
-- Vector.
--
-- The default instance is just a plain old MutVar
-- containing the type. This is a valid instance, but it treats the
-- entire type "wholesale" --- it is basically using it as a non-mutable
-- type. You won't get any of the performance benefits of piecewise
-- mutation from it, but it is useful as a base case for non-composite
-- types like Int.
--
-- There are some built-in alternative options for user-defined ADTs with
-- Generic instances:
--
--
-- -- Works for all Generic instances, preserves piecewise mutation
-- -- for products
-- type Ref m a = GRef m a
--
--
-- If you just set up a blank instance, the implementations of
-- thawRef, freezeRef, and copyRef will be inferred
-- using DefaultMutable.
--
--
-- data MyType
--
-- -- The default setup is OK
-- instance Mutable m MyType
--
-- -- This is equivalent to the above
-- instance Mutable m MyType
-- type Ref m MyType = MutVar (PrimState m) MyType
--
-- -- any Generic instance
-- data MyType = MyType { mtInt :: Int, mtDouble :: Double }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- See https://mutable.jle.im/02-mutable-and-ref.html for more
-- information on this type family and how to define instances
-- automatically.
type family Ref m a = (v :: Type) | v -> a;
type Ref m a = MutVar (PrimState m) a;
}
-- | Thaw a pure/persistent value into its mutable version, which
-- can be manipulated using modifyRef or other methods specific
-- for that type (like read).
--
-- Returns the Ref instance, so, for example, for Vector:
--
-- -- thawRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector a -- -> m (Vector s a) ---- -- For non-composite (like Int), this is often called the "new -- var" function, like newIORef / newSTRef / -- newMutVar etc. thawRef :: Mutable m a => a -> m (Ref m a) -- | Freeze a mutable value into its pure/persistent version. -- -- Takes a Ref instance, but type inference will be able to infer -- the pure value's type because Ref is injective. -- -- For example, for Vector: -- --
-- freezeRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector s a -- -> m (Vector a) ---- -- For non-composite (like Int), this is often called the "read -- var" function, like readIORef / readSTRef / -- readMutVar etc. freezeRef :: Mutable m a => Ref m a -> m a -- | Overwrite a mutable value by provivding a pure/persistent value. -- copyRef -- -- Returns the Ref and the value, so, for example, for -- Vector: -- --
-- copyRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector s a -- -> Vector a -- -> m () ---- -- Note that if a is a composite type (with an appropriate -- composite reference), this will be done "piecewise": it'll write to -- each mutable component separately. -- -- For non-composite (like Int), this is often called the "write -- var" function, like writeIORef / writeSTRef / -- writeMutVar etc. copyRef :: Mutable m a => Ref m a -> a -> m () -- | Deep Copy-move a mutable reference on top of another, overwriting the -- second one. -- -- For non-composite types, this is the same as a thawRef and a -- copyRef. For composite types this can be more effficient -- because the copying is done piecewise, so the intermediate pure value -- is never created. moveRef :: Mutable m a => Ref m a -> Ref m a -> m () -- | Create a deep copy of a mutable reference, allocated to a separate -- independent reference. -- -- For non-composite types, this is the same as a thawRef and a -- freezeRef. For composite types this can be more effficient -- because the cloning is done piecewise, so the intermediate pure value -- is never created. cloneRef :: Mutable m a => Ref m a -> m (Ref m a) -- | A non-copying version of thawRef that can be more efficient for -- types where the mutable representation is the same as the immutable -- one (like Vector). -- -- This is safe as long as you never again use the original pure value, -- since it can potentially directly mutate it. unsafeThawRef :: Mutable m a => a -> m (Ref m a) -- | A non-copying version of freezeRef that can be more efficient -- for types where the mutable representation is the same as the -- immutable one (like Vector). -- -- This is safe as long as you never again modify the mutable reference, -- since it can potentially directly mutate the frozen value magically. unsafeFreezeRef :: Mutable m a => Ref m a -> m a -- | Thaw a pure/persistent value into its mutable version, which -- can be manipulated using modifyRef or other methods specific -- for that type (like read). -- -- Returns the Ref instance, so, for example, for Vector: -- --
-- thawRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector a -- -> m (Vector s a) ---- -- For non-composite (like Int), this is often called the "new -- var" function, like newIORef / newSTRef / -- newMutVar etc. thawRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => a -> m (Ref m a) -- | Freeze a mutable value into its pure/persistent version. -- -- Takes a Ref instance, but type inference will be able to infer -- the pure value's type because Ref is injective. -- -- For example, for Vector: -- --
-- freezeRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector s a -- -> m (Vector a) ---- -- For non-composite (like Int), this is often called the "read -- var" function, like readIORef / readSTRef / -- readMutVar etc. freezeRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => Ref m a -> m a -- | Overwrite a mutable value by provivding a pure/persistent value. -- copyRef -- -- Returns the Ref and the value, so, for example, for -- Vector: -- --
-- copyRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector s a -- -> Vector a -- -> m () ---- -- Note that if a is a composite type (with an appropriate -- composite reference), this will be done "piecewise": it'll write to -- each mutable component separately. -- -- For non-composite (like Int), this is often called the "write -- var" function, like writeIORef / writeSTRef / -- writeMutVar etc. copyRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => Ref m a -> a -> m () -- | Deep Copy-move a mutable reference on top of another, overwriting the -- second one. -- -- For non-composite types, this is the same as a thawRef and a -- copyRef. For composite types this can be more effficient -- because the copying is done piecewise, so the intermediate pure value -- is never created. moveRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => Ref m a -> Ref m a -> m () -- | Create a deep copy of a mutable reference, allocated to a separate -- independent reference. -- -- For non-composite types, this is the same as a thawRef and a -- freezeRef. For composite types this can be more effficient -- because the cloning is done piecewise, so the intermediate pure value -- is never created. cloneRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => Ref m a -> m (Ref m a) -- | A non-copying version of thawRef that can be more efficient for -- types where the mutable representation is the same as the immutable -- one (like Vector). -- -- This is safe as long as you never again use the original pure value, -- since it can potentially directly mutate it. unsafeThawRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => a -> m (Ref m a) -- | A non-copying version of freezeRef that can be more efficient -- for types where the mutable representation is the same as the -- immutable one (like Vector). -- -- This is safe as long as you never again modify the mutable reference, -- since it can potentially directly mutate the frozen value magically. unsafeFreezeRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => Ref m a -> m a -- | A default implementation of copyRef using thawRef and -- moveRef. copyRefWhole :: Mutable m a => Ref m a -> a -> m () -- | A default implementation of moveRef that round-trips through -- the pure type, using freezeRef and copyRef. It freezes -- the entire source and then re-copies it into the destination. moveRefWhole :: Mutable m a => Ref m a -> Ref m a -> m () -- | A default implementation of moveRef that round-trips through -- the pure type, using freezeRef and thawRef. It freezes -- the entire source and then re-copies it into the destination. cloneRefWhole :: Mutable m a => Ref m a -> m (Ref m a) -- | Apply a pure function on an immutable value onto a value stored in a -- mutable reference. modifyRef :: Mutable m a => Ref m a -> (a -> a) -> m () -- | modifyRef, but forces the result before storing it back in the -- reference. modifyRef' :: Mutable m a => Ref m a -> (a -> a) -> m () -- | Apply a pure function on an immutable value onto a value stored in a -- mutable reference, returning a result value from that function. updateRef :: Mutable m a => Ref m a -> (a -> (a, b)) -> m b -- | updateRef, but forces the updated value before storing it back -- in the reference. updateRef' :: Mutable m a => Ref m a -> (a -> (a, b)) -> m b -- | Apply a monadic function on an immutable value onto a value stored in -- a mutable reference. Uses copyRef into the reference after the -- action is completed. modifyRefM :: Mutable m a => Ref m a -> (a -> m a) -> m () -- | modifyRefM, but forces the result before storing it back in the -- reference. modifyRefM' :: Mutable m a => Ref m a -> (a -> m a) -> m () -- | Apply a monadic function on an immutable value onto a value stored in -- a mutable reference, returning a result value from that function. Uses -- copyRef into the reference after the action is completed. updateRefM :: Mutable m a => Ref m a -> (a -> m (a, b)) -> m b -- | updateRefM, but forces the updated value before storing it back -- in the reference. updateRefM' :: Mutable m a => Ref m a -> (a -> m (a, b)) -> m b -- | A handy newtype wrapper that allows you to partially apply Ref. -- RefFor m a is the same as Ref m a, but -- can be partially applied. -- -- If used with HKD, you can treat this syntactically identically -- as a Ref m a. newtype RefFor m a RefFor :: Ref m a -> RefFor m a [getRefFor] :: RefFor m a -> Ref m a -- | The default implementations of thawRef, freezeRef, and -- copyRef dispatched for different choices of Ref. -- -- Basically, by specifying Ref, you get the rest of the instance -- for free. -- -- We have the default case: -- --
-- -- default, if you don't specify Ref -- instance Mutable m MyType -- -- -- the above is the same as: -- instance Mutable m MyType -- type Ref m MyType = MutVar (PrimState m) MyType ---- -- The case for any instance of Generic: -- --
-- instance Mutable m MyType -- type Ref m MyType = GRef m MyType ---- -- The case for the "higher-kinded data" pattern a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/: -- --
-- instance Mutable m (MyTypeF Identity) -- type Ref m (MyTypeF Identity) = MyTypeF (RefFor m) ---- -- The case for any newtype wrapper: -- --
-- newtype MyType = MT (Vector Double) -- -- instance Mutable m MyType where -- type Ref m MyType = CoerceRef m MyType (Vector Double) ---- -- And the case for any 'Traversable instance, where the items will all -- be mutable references: -- --
-- data MyContainer a = MC a a a a -- deriving (Functor, Foldable, Traversable) -- -- instance Mutable m a => Mutable m (MyContainer a) where -- type Ref m (MyContainer a) = TraverseRef m MyContainer a --class DefaultMutable m a r | r -> a defaultThawRef :: DefaultMutable m a r => a -> m r defaultFreezeRef :: DefaultMutable m a r => r -> m a defaultCopyRef :: DefaultMutable m a r => r -> a -> m () defaultMoveRef :: DefaultMutable m a r => r -> r -> m () defaultCloneRef :: DefaultMutable m a r => r -> m r defaultUnsafeThawRef :: DefaultMutable m a r => a -> m r defaultUnsafeFreezeRef :: DefaultMutable m a r => r -> m a -- | Newtype wrapper that can provide any type with a Mutable -- instance, giving it a "non-piecewise" instance. Can be useful for -- avoiding orphan instances yet still utilizing auto-deriving features, -- or for overwriting the Mutable instance of other instances. -- -- For example, let's say you want to auto-derive an instance for your -- data type: -- --
-- data MyType = MT Int Double OtherType -- deriving Generic ---- -- This is possible if all of MyTypes fields have Mutable -- instances. However, let's say OtherType comes from an -- external library that you don't have control over, and so you cannot -- give it a Mutable instance without incurring an orphan -- instance. -- -- One solution is to wrap it in VarMut: -- --
-- data MyType = MT Int Double (VarMut OtherType) -- deriving Generic ---- -- This can then be auto-derived: -- --
-- instance Mutable m MyType where -- type Ref m MyType = GRef m MyType ---- -- It can also be used to override a Mutable instance. For -- example, even if the Mutable instance of SomeType is -- piecewise-mutable, the Mutable instance of VarMut -- SomeType will be not be piecewise. -- -- For example, the Mutable instance for String is a -- mutable linked list, but it might be more efficient to treat it as an -- atomic value to update all at once. You can use VarMut -- String to get that Mutable instance. newtype VarMut a VarMut :: a -> VarMut a [getVarMut] :: VarMut a -> a -- | Similar to VarMut, this allows you to overwrite the normal -- Mutable instance of a type to utilize a coercible type's -- Mutable instance instead of its normal instance. It's also -- useful to provide an instance for an externally defined type without -- incurring orphan instances. -- -- For example, if an external library provides -- --
-- newtype DoubleVec = DV (Vector Double) ---- -- and you want to use it following Vectors Mutable -- instance (via MVector), but you don't want to write an orphan -- instance like -- --
-- instance Mutable m DoubleVec where -- type Ref m DoubleVec = CoerceRef m DoubleVec (Vector Double) ---- -- then you can instead use CoerceMut DoubleVec (Vector -- Double) as the data type. This wrapped type does use the -- inderlying Mutable insatnce for Vector. newtype CoerceMut s a CoerceMut :: s -> CoerceMut s a [getCoerceMut] :: CoerceMut s a -> s -- | Similar to VarMut, this allows you to overwrite the normal -- Mutable instance for a type to utilize its Traversable -- instance instead of its normal instance. It's also useful to provide -- an instance for an externally defined type without incurring orphan -- instances. -- -- For example, the instance of Mutable (TraverseMut [] -- a) is a normal list of mutable references, instead of a full-on -- mutable linked list. newtype TraverseMut f a TraverseMut :: f a -> TraverseMut f a [getTraverseMut] :: TraverseMut f a -> f a -- | Similar to VarMut, this allows you to overwrite the normal -- Mutable instance of a type to make it immutable. -- -- For example, let's say you have a type, with the automatically derived -- generic instance of Mutable: -- --
-- data MyType = MT
-- { mtX :: Int
-- , mtY :: Vector Double
-- , mtZ :: String
-- }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- This basically uses three mutable references: the Int, the
-- Vector Double, and the String. However, you
-- might want the Mutable instance of MyType to be
-- immutable String field, and so it cannot be updated at
-- all even when thawed. To do that, you can instead have:
--
--
-- data MyType = MT
-- { mtX :: Int
-- , mtY :: Vector Double
-- , mtZ :: Immutable String
-- }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- which has that behavior. The Int and the Vector will be
-- mutable within Ref m MyType, but not the
-- String.
newtype Immutable a
Immutable :: a -> Immutable a
[getImmutable] :: Immutable a -> a
-- | If you can provice a natural transformation from m to
-- n, you should be able to use a value as if it had
-- Mutable n a if you have Mutable m a.
reMutable :: forall m n a r. (Mutable m a, Monad n) => (forall x. m x -> n x) -> (Mutable n a => r) -> r
-- | If you can provice a natural transformation from m to
-- n, then Mutable m a should also imply
-- Mutable n a.
reMutableConstraint :: forall m n a. (Mutable m a, Monad n) => (forall x. m x -> n x) -> Mutable m a :- Mutable n a
-- | Useful type family to Ref m over every item in a
-- type-level list
--
-- -- ghci> :kind! MapRef IO '[Int, V.Vector Double] -- '[ MutVar RealWorld Int, MVector RealWorld Double ] --type family MapRef m as instance Data.Traversable.Traversable f => Data.Traversable.Traversable (Data.Mutable.Class.TraverseMut f) instance Data.Foldable.Foldable f => Data.Foldable.Foldable (Data.Mutable.Class.TraverseMut f) instance GHC.Base.Functor f => GHC.Base.Functor (Data.Mutable.Class.TraverseMut f) instance forall k (f :: k -> *) (a :: k). GHC.Generics.Generic (Data.Mutable.Class.TraverseMut f a) instance forall k (f :: k -> *) (a :: k). GHC.Classes.Ord (f a) => GHC.Classes.Ord (Data.Mutable.Class.TraverseMut f a) instance forall k (f :: k -> *) (a :: k). GHC.Classes.Eq (f a) => GHC.Classes.Eq (Data.Mutable.Class.TraverseMut f a) instance forall k (f :: k -> *) (a :: k). GHC.Show.Show (f a) => GHC.Show.Show (Data.Mutable.Class.TraverseMut f a) instance (GHC.Base.Monad n, Data.Mutable.Internal.Mutable m a, Data.Reflection.Reifies s (Data.Mutable.Class.ReMutableTrans m n)) => Data.Mutable.Internal.Mutable n (Data.Mutable.Class.ReMutable s m a) instance Data.Vinyl.XRec.IsoHKD Data.Mutable.Class.Immutable a instance GHC.Base.Monad m => Data.Mutable.Internal.Mutable m (Data.Mutable.Class.Immutable a) instance forall k s (a :: k). Data.Vinyl.XRec.IsoHKD (Data.Mutable.Class.CoerceMut s) a instance (Data.Mutable.Internal.Mutable m a, GHC.Types.Coercible s a) => Data.Mutable.Internal.Mutable m (Data.Mutable.Class.CoerceMut s a) instance forall k (f :: k -> *) (a :: k). Data.Vinyl.XRec.IsoHKD (Data.Mutable.Class.TraverseMut f) a instance (Data.Traversable.Traversable f, Data.Mutable.Internal.Mutable m a) => Data.Mutable.Internal.Mutable m (Data.Mutable.Class.TraverseMut f a) instance Data.Vinyl.XRec.IsoHKD Data.Mutable.Class.VarMut a instance Control.Monad.Primitive.PrimMonad m => Data.Mutable.Internal.Mutable m (Data.Mutable.Class.VarMut a) -- | Tools for working with potential branches of piecewise-mutable values. -- -- If Data.Mutable.Parts is for product types, then -- Data.Mutable.Branches is for sum types. -- -- See https://mutable.jle.im/06-mutable-branches.html for an -- introduction to this module. module Data.Mutable.Branches -- | A MutBranch m s a represents the information that -- s could potentially be an a. Similar in spirit to a -- Prism' s a. -- -- MutBranch m s a means that a is one potential -- option that s could be in, or that s is a sum type -- and a is one of the branches/constructors. -- -- See https://mutable.jle.im/06-mutable-branches.html for an -- introduction to this module. -- -- If MutPart is for product types, then MutBranch is for -- sum types. -- -- In this case, "branch" means "potential option". For example, the -- branches of Either are Left and Right. -- -- The simplest way to make these is by using constrMB. For -- instance, to get the two branches of an Either: -- --
-- constrMB #_Left :: MutBranch m (Either a b) a -- constrMB #_Right :: MutBranch m (Either a b) b ---- --
-- ghci> r <- thawRef (Left 10) -- ghci> freezeBranch (constrMB #_Left) r -- Just 10 -- ghci> freezeBranch (constrMB #_Right) r -- Nothing ---- -- It uses OverloadedLabels, but requires an underscore before the -- constructor name due to limitations in the extension. -- -- One nice way to use these is with withBranch_: -- --
-- ghci> r <- thawRef (Just 10) -- ghci> withBranch_ (constrMB #_Just) $ i -> -- i is an Int ref -- .. modifyRef i (+ 1) -- ghci> freezeRef r -- Just 11 ---- --
-- ghci> r <- thawRef Nothing -- ghci> withBranch_ (constrMB #_Just) $ i -> -- i is an Int ref -- .. modifyRef i (+ 1) -- ghci> freezeRef r -- Nothing ---- -- Perhaps the most useful usage of this abstraction is for recursive -- data types. -- --
-- data List a = Nil | Cons a (List a) -- deriving Generic -- -- instance Mutable m a => Mutable m (List a) where -- type Ref m (List a) = GRef m (List a) ---- -- GRef m (List a) is now a mutable linked list! Once we -- make the MutBranch for the nil and cons cases: -- --
-- nilBranch :: MutBranch m (List a) () -- nilBranch = constrMB #_Nil -- -- consBranch :: MutBranch m (List a) (a, List a) -- consBranch = constrMB #_Cons ---- -- Here is a function to check if a linked list is currently empty: -- --
-- isEmpty -- :: (PrimMonad m, Mutable m a) -- => Ref m (List a) -- -> m Bool -- isEmpty = hasBranch nilBranch ---- -- Here is one to "pop" a mutable linked list, giving us the first value -- and shifting the rest of the list up. -- --
-- popStack -- :: (PrimMonad m, Mutable m a) -- => Ref m (List a) -- -> m (Maybe a) -- popStack r = do -- c <- projectBranch consBranch r -- case c of -- Nothing -> pure Nothing -- Just (x, xs) -> do -- moveRef r xs -- Just $ freezeRef x ---- -- And here is a function to concatenate a second linked list to the end -- of a first one. -- --
-- concatLists -- :: (PrimMonad m, Mutable m a) -- => Ref m (List a) -- -> Ref m (List a) -- -> m () -- concatLists l1 l2 = do -- c <- projectBranch consBranch l1 -- case c of -- Nothing -> moveRef l1 l2 -- Just (_, xs) -> concatLists xs l2 --data MutBranch m s a MutBranch :: (Ref m s -> m (Maybe (Ref m a))) -> (Ref m a -> m (Ref m s)) -> MutBranch m s a -- | With a MutBranch, attempt to get the mutable contents of a -- branch of a mutable s, if possible. -- --
-- ghci> r <- thawRef (Left 10) -- ghci> s <- projectBranch (constrMB #_Left) r -- ghci> case s of Just s' -> freezeRef s' -- 10 ---- --
-- ghci> r <- thawRef (Right True) -- ghci> s <- projectBranch (constrMB #_Left) r -- ghci> case s of Nothing -> "it was Right" -- "it was Right" --[projectBranch] :: MutBranch m s a -> Ref m s -> m (Maybe (Ref m a)) -- | Embed an a ref as a part of a larger s ref. Note -- that this does not copy or clone: any mutations to the -- a ref will be reflected in the s ref, as long as the -- s ref maintains the reference. -- --
-- ghci> r <- thawRef 100 -- ghci> s <- embedBranch (constMB #_Left) r -- ghci> freezeRef s -- Left 100 -- ghci> modifyRef r (+ 1) -- ghci> freezeRef s -- Left 101 ---- -- Any mutations on s (as long as they keep the same branch) -- will also affect a: -- --
-- ghci> copyRef s (Left 0) -- ghci> freezeRef r -- 0 ---- -- However, "switching branches" on an Either ref will cause it to -- loose the original reference: -- --
-- ghci> copyRef s (Right True) -- ghci> copyRef s (Left 999) -- ghci> freezeRef r -- 0 --[embedBranch] :: MutBranch m s a -> Ref m a -> m (Ref m s) -- | With a MutBranch, thaw an a into a mutable s -- on that branch. -- --
-- ghci> r <- thawBranch (constrMB #_Left) 10 -- ghci> freezeRef r -- Left 10 --thawBranch :: Mutable m a => MutBranch m s a -> a -> m (Ref m s) -- | With a MutBranch, read out a specific a branch of an -- s, if it exists. -- --
-- ghci> r <- thawRef (Left 10) -- ghci> freezeBranch (constrMB #_Left) r -- Just 10 -- ghci> freezeBranch (constrMB #_Right) r -- Nothing --freezeBranch :: Mutable m a => MutBranch m s a -> Ref m s -> m (Maybe a) -- | Check if an s is currently a certain branch a. hasBranch :: Mutable m a => MutBranch m s a -> Ref m s -> m Bool -- | Check if an s is not currently a certain branch -- a. hasn'tBranch :: Mutable m a => MutBranch m s a -> Ref m s -> m Bool -- | With a MutBranch, overwrite an s as an a, on -- that branch. -- --
-- ghci> r <- thawRef (Left 10) -- ghci> s <- thawRef 100 -- ghci> moveBranch (constrMB #_Left) r s -- ghci> freezeRef r -- Left 100 -- ghci> t <- thawRef True -- ghci> moveBranch (constrMB #_Right) r t -- ghci> freezeRef r -- Right True --moveBranch :: Mutable m s => MutBranch m s a -> Ref m s -> Ref m a -> m () -- | With a MutBranch, set s to have the branch -- a. -- --
-- ghci> r <- thawRef (Left 10) -- ghci> copyBranch (constrMB #_Left) r 5678 -- ghci> freezeRef r -- Left 5678 -- ghci> copyBranch (constrMB #_Right) r True -- ghci> freezeRef r -- Right True --copyBranch :: (Mutable m s, Mutable m a) => MutBranch m s a -> Ref m s -> a -> m () -- | With a MutBranch, attempt to clone out a branch of a mutable -- s, if possible. -- --
-- ghci> r <- thawRef (Left 10) -- ghci> s <- cloneBranch (constrMB #_Left) -- ghci> case s of Just s' -> freezeRef s' -- 10 ---- --
-- ghci> r <- thawRef (Right True) -- ghci> s <- cloneBranch (constrMB #_Left) -- ghci> case s of Nothing -> "it was Right" -- "it was Right" --cloneBranch :: Mutable m a => MutBranch m s a -> Ref m s -> m (Maybe (Ref m a)) -- | A non-copying version of thawBranch that can be more efficient -- for types where the mutable representation is the same as the -- immutable one (like Vector). -- -- This is safe as long as you never again use the original pure value, -- since it can potentially directly mutate it. unsafeThawBranch :: Mutable m a => MutBranch m s a -> a -> m (Ref m s) -- | A non-copying version of freezeBranch that can be more -- efficient for types where the mutable representation is the same as -- the immutable one (like Vector). -- -- This is safe as long as you never again modify the mutable reference, -- since it can potentially directly mutate the frozen value magically. unsafeFreezeBranch :: Mutable m a => MutBranch m s a -> Ref m s -> m (Maybe a) -- | With a MutBranch, if an s is on the a branch, -- perform an action on the a reference and overwrite the -- s with the modified a. Returns the result of the -- action, if a was found. -- --
-- ghci> r <- thawRef (Just 10) -- ghci> withBranch_ (constrMB #_Just) $ i -> -- i is an Int ref -- .. modifyRef i (+ 1) -- ghci> freezeRef r -- Just 11 ---- --
-- ghci> r <- thawRef Nothing -- ghci> withBranch_ (constrMB #_Just) $ i -> -- i is an Int ref -- .. modifyRef i (+ 1) -- ghci> freezeRef r -- Nothing --withBranch :: Mutable m a => MutBranch m s a -> Ref m s -> (Ref m a -> m b) -> m (Maybe b) -- | withBranch, but discarding the returned value. withBranch_ :: Mutable m a => MutBranch m s a -> Ref m s -> (Ref m a -> m b) -> m () -- | With a MutBranch, run a pure function over a potential branch -- a of s. If s is not on that branch, leaves -- s unchanged. -- --
-- ghci> r <- thawRef (Just 10) -- ghci> modifyBranch (constrMB #_Just) r (+ 1) -- ghci> freezeRef r -- Just 11 ---- --
-- ghci> r <- thawRef Nothing -- ghci> modifyBranch (constrMB #_Just) r (+ 1) -- ghci> freezeRef r -- Nothing --modifyBranch :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> a) -> m () -- | modifyBranch, but forces the result before storing it back in -- the reference. modifyBranch' :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> a) -> m () -- | With a MutBranch, run a pure function over a potential branch -- a of s. The function returns the updated a -- and also an output value to observe. If s is not on that -- branch, leaves s unchanged. -- --
-- ghci> r <- thawRef (Just 10) -- ghci> updateBranch (constrMB #_Just) r $ i -> (i + 1, show i) -- Just "10" -- ghci> freezeRef r -- Just 11 ---- --
-- ghci> r <- thawRef Nothing -- ghci> updateBranch (constrMB #_Just) r $ i -> (i + 1, show i) -- Nothing -- ghci> freezeRef r -- Nothing --updateBranch :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> (a, b)) -> m (Maybe b) -- | updateBranch, but forces the result before storing it back in -- the reference. updateBranch' :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> (a, b)) -> m (Maybe b) -- | modifyBranch but for a monadic function. Uses copyRef -- into the reference after the action is completed. modifyBranchM :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> m a) -> m () -- | modifyBranchM, but forces the result before storing it back in -- the reference. modifyBranchM' :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> m a) -> m () -- | updateBranch but for a monadic function. Uses copyRef -- into the reference after the action is completed. updateBranchM :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> m (a, b)) -> m (Maybe b) -- | updateBranchM, but forces the result before storing it back in -- the reference. updateBranchM' :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> m (a, b)) -> m (Maybe b) -- | Compose two MutBranchs, to drill down on what is being focused. compMB :: Monad m => MutBranch m a b -> MutBranch m b c -> MutBranch m a c -- | An identity MutBranch, treating the item itself as a whole -- branch. cloneBranch will always "match". idMB :: Applicative m => MutBranch m a a -- | Create a MutBranch for any data type with a Generic -- instance by specifying the constructor name using OverloadedLabels -- --
-- ghci> r <- thawRef (Left 10) -- ghci> freezeBranch (constrMB #_Left) r -- Just 10 -- ghci> freezeBranch (constrMB #_Right) r -- Nothing ---- -- Note that due to limitations in OverloadedLabels, you must prefix the -- constructor name with an undescore. -- -- There also isn't currently any way to utilize OverloadedLabels with -- operator identifiers, so using it with operator constructors (like -- : and []) requires explicit TypeApplications: -- --
-- -- | MutBranch focusing on the cons case of a list -- consMB :: (PrimMonad m, Mutable m a) => MutBranch m [a] (a, [a]) -- consMB = constrMB (CLabel @":") --constrMB :: forall ctor m s a. (Ref m s ~ GRef m s, GMutBranchConstructor ctor m (Rep s) a) => CLabel ctor -> MutBranch m s a -- | A version of Label that removes an underscore at the beginning -- when used with -XOverloadedLabels. Used to specify constructors, since -- labels are currently not able to start with capital letters. data CLabel (ctor :: Symbol) CLabel :: CLabel (ctor :: Symbol) -- | Typeclass powering constrMB using GHC Generics. -- -- Heavily inspired by Data.Generics.Sum.Constructors. class (GMutable m f, Mutable m a) => GMutBranchConstructor (ctor :: Symbol) m f a | ctor f -> a -- | Useful type family to Ref m over every item in a -- type-level list -- --
-- ghci> :kind! MapRef IO '[Int, V.Vector Double] -- '[ MutVar RealWorld Int, MVector RealWorld Double ] --type family MapRef m as -- | MutBranch focusing on the nil case of a list nilMB :: (PrimMonad m, Mutable m a) => MutBranch m [a] () -- | MutBranch focusing on the cons case of a list consMB :: (PrimMonad m, Mutable m a) => MutBranch m [a] (a, [a]) -- | MutBranch focusing on the Nothing case of a Maybe nothingMB :: (PrimMonad m, Mutable m a) => MutBranch m (Maybe a) () -- | MutBranch focusing on the Just case of a Maybe justMB :: (PrimMonad m, Mutable m a) => MutBranch m (Maybe a) a -- | MutBranch focusing on the Left case of an Either leftMB :: (PrimMonad m, Mutable m a, Mutable m b) => MutBranch m (Either a b) a -- | MutBranch focusing on the Right case of an Either rightMB :: (PrimMonad m, Mutable m a, Mutable m b) => MutBranch m (Either a b) b instance forall k (m :: * -> *) a (ctor :: GHC.Types.Symbol) (l :: k -> *) (r :: k -> *). (Control.Monad.Primitive.PrimMonad m, Data.Mutable.Internal.Mutable m a, Data.Mutable.Branches.GMutBranchSum ctor (Data.Generics.Internal.Families.Has.HasCtorP ctor l) m l r a) => Data.Mutable.Branches.GMutBranchConstructor ctor m (l GHC.Generics.:+: r) a instance (Control.Monad.Primitive.PrimMonad m, Data.Mutable.Internal.GMutable m r, Data.Mutable.Branches.GMutBranchConstructor ctor m l a, Data.Generics.Product.Internal.HList.GIsList (Data.Mutable.Internal.GRef_ m l) (Data.Mutable.Internal.GRef_ m l) (Data.Mutable.Instances.MapRef m as) (Data.Mutable.Instances.MapRef m as), Data.Generics.Product.Internal.HList.GIsList l l as as, Data.Generics.Product.Internal.HList.ListTuple a a as as, Data.Generics.Product.Internal.HList.ListTuple b b (Data.Mutable.Instances.MapRef m as) (Data.Mutable.Instances.MapRef m as), Data.Mutable.Internal.Ref m a GHC.Types.~ b) => Data.Mutable.Branches.GMutBranchSum ctor 'GHC.Types.True m l r a instance (Control.Monad.Primitive.PrimMonad m, Data.Mutable.Internal.GMutable m l, Data.Mutable.Branches.GMutBranchConstructor ctor m r a, Data.Generics.Product.Internal.HList.GIsList (Data.Mutable.Internal.GRef_ m r) (Data.Mutable.Internal.GRef_ m r) (Data.Mutable.Instances.MapRef m as) (Data.Mutable.Instances.MapRef m as), Data.Generics.Product.Internal.HList.GIsList r r as as, Data.Generics.Product.Internal.HList.ListTuple a a as as, Data.Generics.Product.Internal.HList.ListTuple b b (Data.Mutable.Instances.MapRef m as) (Data.Mutable.Instances.MapRef m as), Data.Mutable.Internal.Ref m a GHC.Types.~ b) => Data.Mutable.Branches.GMutBranchSum ctor 'GHC.Types.False m l r a instance (Data.Mutable.Internal.GMutable m f, Data.Mutable.Internal.Mutable m a, Data.Generics.Product.Internal.HList.GIsList (Data.Mutable.Internal.GRef_ m f) (Data.Mutable.Internal.GRef_ m f) (Data.Mutable.Instances.MapRef m as) (Data.Mutable.Instances.MapRef m as), Data.Generics.Product.Internal.HList.GIsList f f as as, Data.Generics.Product.Internal.HList.ListTuple a a as as, Data.Generics.Product.Internal.HList.ListTuple b b (Data.Mutable.Instances.MapRef m as) (Data.Mutable.Instances.MapRef m as), Data.Mutable.Internal.Ref m a GHC.Types.~ b) => Data.Mutable.Branches.GMutBranchConstructor ctor m (GHC.Generics.M1 GHC.Generics.C ('GHC.Generics.MetaCons ctor fixity fields) f) a instance forall k (ctor :: GHC.Types.Symbol) (m :: * -> *) (f :: k -> *) a (meta :: GHC.Generics.Meta). Data.Mutable.Branches.GMutBranchConstructor ctor m f a => Data.Mutable.Branches.GMutBranchConstructor ctor m (GHC.Generics.M1 GHC.Generics.D meta f) a instance (ctor_ GHC.Types.~ GHC.TypeLits.AppendSymbol "_" ctor) => GHC.OverloadedLabels.IsLabel ctor_ (Data.Mutable.Branches.CLabel ctor) -- | Tools for working with individual components of piecewise-mutable -- values. -- -- If Data.Mutable.Branches is for sum types, then -- Data.Mutable.Parts is for sum types. -- -- See https://mutable.jle.im/05-mutable-parts.html for an -- introduction to this module. module Data.Mutable.Parts -- | A MutPart m s a is a way to "zoom into" an a, -- as a part of a mutable reference on s. This allows you to -- only modify a single a part of the s, without -- touching the rest. It's spiritually similar to a Lens' s a. -- -- If MutBranch is for sum types, then MutPart is for -- product types. -- -- See https://mutable.jle.im/05-mutable-parts.html for an -- introduction to this type. -- -- An example that is commonly found in the ecosystem is something like -- (flipped) write :: Int -> MVector s a -> a -> m -- () from Data.Vector.Mutable --- write 3 :: -- MVector s a -> a -> m (), for instance, lets you -- modify a specific part of the vector without touching the rest. -- -- You would use a MutPart using freezePart, -- copyPart, modifyPart, etc. -- -- For non-composite types, there won't really be any meaningful values. -- However, we have them for many composite types. For example, for -- tuples: -- --
-- mutFst :: MutPart m (a, b) a -- mutSnd :: MutPart m (a, b) b ---- --
-- ghci> r <- thawRef (2, 4) -- ghci> copyPart mutFst r 100 -- ghci> freezeRef r -- (100, 4) ---- -- If you are using GRef as an automatically-defined mutable -- reference, then the easiest way to create these for your mutable types -- are with fieldMut and posMut. -- -- If you are using the "Higher-kinded data" pattern, then there's an -- easy way to generate a MutPart for every single field, if you -- have a product type --- see hkdMutParts for more information. newtype MutPart m s a MutPart :: (Ref m s -> Ref m a) -> MutPart m s a [getMutPart] :: MutPart m s a -> Ref m s -> Ref m a -- | Using a MutPart, perform a function on a Ref m -- s as if you had a Ref m a. withPart :: MutPart m s a -> Ref m s -> (Ref m a -> m r) -> m r -- | With a MutPart, read out a specific part of a Ref. freezePart :: Mutable m a => MutPart m s a -> Ref m s -> m a -- | With a MutPart, overwrite into a specific part of a Ref. copyPart :: Mutable m a => MutPart m s a -> Ref m s -> a -> m () -- | With a MutPart, copy a Ref containing a subvalue into a -- specific part of a larger Ref. -- --
-- data MyType = MT { mtInt :: Int, mtDouble :: Double }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- -- ghci> x <- thawRef $ MyType 3 4.5 -- ghci> y <- thawRef $ 100 -- ghci> movePartInto (fieldMut #mtInt) x y -- ghci> freezeRef x -- MyType 100 4.5 --movePartInto :: Mutable m a => MutPart m s a -> Ref m s -> Ref m a -> m () -- | With a MutPart, copy a specific part of a larger Ref -- into a Ref of the smaller subvalue value. -- --
-- data MyType = MT { mtInt :: Int, mtDouble :: Double }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- -- ghci> x <- thawRef $ MyType 3 4.5 -- ghci> y <- thawRef $ 100 -- ghci> movePartOver (fieldMut #mtInt) y x -- ghci> freezeRef y -- 3 --movePartOver :: Mutable m a => MutPart m s a -> Ref m a -> Ref m s -> m () -- | With a MutPart, copy a specific part of a large Ref into -- that same part in another large Ref. -- --
-- data MyType = MT { mtInt :: Int, mtDouble :: Double }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- -- ghci> x <- thawRef $ MyType 3 4.5 -- ghci> y <- thawRef $ MyType 100 12.34 -- ghci> movePartWithin (fieldMut #mtInt) x y -- ghci> freezeRef x -- MyType 100 4.5 --movePartWithin :: Mutable m a => MutPart m s a -> Ref m s -> Ref m s -> m () -- | Clone out a subvalue of a larger Ref. clonePart :: Mutable m a => MutPart m s a -> Ref m s -> m (Ref m a) -- | A non-copying version of unsafeFreezeRef that can be more -- efficient for types where the mutable representation is the same as -- the immutable one (like Vector). -- -- This is safe as long as you never again modify the mutable reference, -- since it can potentially directly mutate the frozen value magically. unsafeFreezePart :: Mutable m a => MutPart m s a -> Ref m s -> m a -- | With a MutPart, modify a specific part of a Ref with a -- pure function. modifyPart :: Mutable m a => MutPart m s a -> Ref m s -> (a -> a) -> m () -- | modifyPart, but forces the result before storing it back in the -- reference. modifyPart' :: Mutable m a => MutPart m s a -> Ref m s -> (a -> a) -> m () -- | updateRef, under a MutPart to only modify a specific -- part of a Ref. updatePart :: Mutable m a => MutPart m s a -> Ref m s -> (a -> (a, b)) -> m b -- | updatePart, but forces the result before storing it back in the -- reference. updatePart' :: Mutable m a => MutPart m s a -> Ref m s -> (a -> (a, b)) -> m b -- | With a MutPart, modify a specific part of a Ref with a -- monadic function. Uses copyRef into the reference after the -- action is completed. modifyPartM :: Mutable m a => MutPart m s a -> Ref m s -> (a -> m a) -> m () -- | modifyPartM, but forces the result before storing it back in -- the reference. modifyPartM' :: Mutable m a => MutPart m s a -> Ref m s -> (a -> m a) -> m () -- | updateRefM, under a MutPart to only modify a specific -- part of a Ref. copyRef into the reference after the -- action is completed. updatePartM :: Mutable m a => MutPart m s a -> Ref m s -> (a -> m (a, b)) -> m b -- | updatePartM, but forces the result before storing it back in -- the reference. updatePartM' :: Mutable m a => MutPart m s a -> Ref m s -> (a -> m (a, b)) -> m b -- | Compose two MutParts one after the other. -- -- Note this is also available (albeit flipped in arguments) through the -- Category instance. compMP :: MutPart m a b -> MutPart m b c -> MutPart m a c infixr 9 `compMP` -- | The identity MutPart: simply focus into the same type itself. -- -- Note this is also available through the Category instance. idMP :: MutPart m a a -- | MutPart into the first field of a tuple reference. mutFst :: MutPart m (a, b) a -- | MutPart into the second field of a tuple reference. mutSnd :: MutPart m (a, b) b -- | Create a MutPart for a field name. Should work for any type -- with one constructor whose mutable reference is GRef. See -- fieldMut for usage directions. -- -- Mostly leverages the power of Data.Generics.Product.Fields. class (Mutable m s, Mutable m a) => FieldMut (fld :: Symbol) m s a | fld s -> a -- | Create a MutPart for a field name. Should work for any type -- with one constructor whose mutable reference is GRef. -- -- Is meant to be used with OverloadedLabels: -- --
-- data MyType = MyType { mtInt :: Int, mtDouble :: Double }
-- deriving (Generic, Show)
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- -- ghci> r <- thawRef (MyType 3 4.5) -- ghci> freezePart (fieldMut #mtInt) r -- 3 -- ghci> copyPart (fieldMut #mtDouble) 1.23 -- ghci> freezeRef r -- MyType 3 1.23 ---- -- However, you can use it without OverloadedLabels by using Label -- with TypeApplications: -- --
-- ghci> freezePart (fieldMut (Label @"mtInt")) r -- 3 ---- -- This and posMut are the main ways to generate a MutPart -- for a type whose mutable reference is GRef. Note that because -- all of the lookups are done at compile-time, fieldMut and -- posMut have more or less identical performance characteristics. fieldMut :: FieldMut fld m s a => Label fld -> MutPart m s a -- | A helpful wrapper over withPart (fieldMut -- #blah). Create a fieldMut and directly use it. withField :: FieldMut fld m s a => Label fld -> Ref m s -> (Ref m a -> m b) -> m b -- | A helpful wrapper around getMutPart (fieldMut -- #blah). Directly use a fieldMut to access a mutable field. mutField :: forall fld m s a. FieldMut fld m s a => Label fld -> Ref m s -> Ref m a -- | Proxy for label type data Label (a :: Symbol) Label :: Label (a :: Symbol) -- | Create a MutPart for a position in a product type. Should work -- for any type with one constructor whose mutable reference is -- GRef. See posMut for usage directions. -- -- Mostly leverages the power of Data.Generics.Product.Positions. class (Mutable m s, Mutable m a) => PosMut (i :: Nat) m s a | i s -> a -- | Create a MutPart for a position in a product type. Should work -- for any type with one constructor whose mutable reference is -- GRef. -- -- Meant to be used with TypeApplications: -- --
-- data MyType = MyType Int Double -- deriving (Generic, Show) -- -- instance Mutable m MyType where -- type Ref m MyType = GRef m MyType ---- --
-- ghci> r <- thawRef (MyType 3 4.5) -- ghci> freezePart (posMut @1) r -- 3 -- ghci> copyPart (posMut @2) 1.23 -- ghci> freezeRef r -- MyType 3 1.23 ---- -- This and fieldMut are the main ways to generate a -- MutPart for a type whose mutable reference is GRef. Note -- that because all of the lookups are done at compile-time, -- posMut and fieldMut have more or less identical -- performance characteristics. posMut :: PosMut i m s a => MutPart m s a -- | A helpful wrapper over withPart (posMut @n). -- Create a posMut and directly use it. withPos :: forall i m s a r. PosMut i m s a => Ref m s -> (Ref m a -> m r) -> m r -- | A helpful wrapper around getMutPart (posMut -- @n). Directly use a posMut to access a mutable field. mutPos :: forall i m s a. PosMut i m s a => Ref m s -> Ref m a -- | Create a MutPart splitting out a product type into a tuple of -- refs for every field in that product type. Should work for any type -- with one constructor whose mutable reference is GRef. See -- tupleMut for usage directions. -- -- Mostly leverages the power of Data.Generics.Product.HList. class (Mutable m s, Mutable m a) => TupleMut m s a | s -> a -- | Create a MutPart splitting out a product type into a tuple of -- refs for every field in that product type. Should work for any type -- with one constructor whose mutable reference is GRef. -- -- Probably most easily used using withTuple: -- --
-- data MyType = MyType Int Double -- deriving (Generic, Show) -- -- instance Mutable m MyType where -- type Ref m MyType = GRef m MyType ---- -- Now there is an instance of TupleMut m MyType (Int, -- Double). -- --
-- ghci> r <- thawRef (MyType 3 4.5) -- ghci> withTuple r $ (rI, rD) -> do -- .. modifyRef rI negate -- .. modifyRef rD (* 2) -- ghci> freezeRef r -- MyType (-3) 9 ---- -- As can be seen, within the lambda, we can get access to every mutable -- reference inside a MyType reference. -- -- Performance-wise, this appears to be faster than fieldMut and -- posMut when using a single reference, but slower if using all -- references. tupleMut :: TupleMut m s a => MutPart m s a -- | A helpful wrapper over withPart tupleMut. -- Directly operate on the items in the data type, getting the references -- as a tuple. See tupleMut for more details on when this should -- work. -- --
-- data MyType = MyType Int Double -- deriving (Generic, Show) -- -- instance Mutable m MyType where -- type Ref m MyType = GRef m MyType ---- --
-- ghci> r <- thawRef (MyType 3 4.5) -- ghci> withTuple r $ (rI, rD) -> do -- .. modifyRef rI negate -- .. modifyRef rD (* 2) -- ghci> freezeRef r -- MyType (-3) 9 --withTuple :: TupleMut m s a => Ref m s -> (Ref m a -> m r) -> m r -- | If you are using the "higher-kinded data" pattern, a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/, and -- you have the appropriate instance for Ref, then you can use -- this to generate a MutPart for every field, if you have a type -- with only one constructor. -- --
-- data MyTypeF f = MT
-- { mtInt :: f Int
-- , mtDouble :: f Double
-- }
-- deriving Generic
--
-- instance Mutable (MyTypeF Identity) where
-- type Ref (MyTypeF Identity) = MyTypeF (RefFor m)
--
-- mx :: MutPart m (MyTypeF Identity) (Vector Int)
-- my :: MutPart m (MyTypeF Identity) (Vector Double)
-- MT mx my = hkdMutParts @MyTypeF
--
--
-- -- ghci> r <- thawRef (MT 3 4.5) -- ghci> freezePart mx r -- 3 -- ghci> copyPart (mtDouble (hkdMutParts @MyTypeF)) r 12.3 -- ghci> freezeRef r -- MT 3 12.3 ---- -- Performance-wise, this is about equivalent to fieldMut and -- posMut for the most part, so the main advantage would be purely -- syntactical. If performance is an issue, you should benchmark all the -- different ways just to be sure. As a general rule, it seems like deep -- nested accesses are faster with composition of fieldMut and -- posMut, but immediate shallow access is often faster with -- hkdMutParts...but this probably does vary on a case-by-case -- basis. hkdMutParts :: forall z m. (Generic (z (RefFor m)), Generic (z (MutPart m (z Identity))), HKDMutParts m z (Rep (z (RefFor m))) (Rep (z (MutPart m (z Identity))))) => z (MutPart m (z Identity)) -- | Typeclass used to implement hkdMutParts. See documentation of -- hkdMutParts for more information. class (Mutable m (z Identity), Ref m (z Identity) ~ z (RefFor m)) => HKDMutParts m z i o -- | A MutPart for a field in a vinyl Rec, automatically -- generated as the first field with a matching type. This is polymorphic -- to work over both Rec and ARec. -- --
-- ghci> r <- thawRef $ [1,2,3] :& [True, False] :& RNil -- ghci> modifyPart (mutRec @Bool) r reverse -- ghci> freezeRef r -- [1,2,3] :& [False, True] :& RNil --mutRec :: forall a as f rec m. (Ref m (rec f as) ~ rec (RecRef m f) as, RecElem rec a a as as (RIndex a as), RecElemFCtx rec (RecRef m f)) => MutPart m (rec f as) (f a) -- | A MutPart to get into a CoerceRef. coerceRef :: Ref m s ~ CoerceRef m s a => MutPart m s a -- | Handy wrapper over getMutPart coerceRef. withCoerceRef :: CoerceRef m s a -> (Ref m a -> m r) -> m r -- | Useful type family to Ref m over every item in a -- type-level list -- --
-- ghci> :kind! MapRef IO '[Int, V.Vector Double] -- '[ MutVar RealWorld Int, MVector RealWorld Double ] --type family MapRef m as instance (Data.Mutable.Internal.Mutable m s, Data.Mutable.Internal.Mutable m a, Data.Mutable.Internal.Ref m s GHC.Types.~ Data.Mutable.Internal.GRef m s, gref GHC.Types.~ Data.Mutable.Parts.Fst (Data.Mutable.Parts.Traverse (Data.Mutable.Internal.GRef_ m (Data.Generics.Product.Internal.Positions.CRep s)) 1), GHC.Types.Coercible (Data.Mutable.Internal.GRef_ m (GHC.Generics.Rep s) ()) (gref ()), Data.Generics.Product.Internal.GLens.GLens' (Data.Mutable.Parts.HasTotalPositionPSym i) gref (Data.Mutable.Internal.Ref m a), Data.Generics.Product.Positions.HasPosition' i s a) => Data.Mutable.Parts.PosMut i m s a instance (Data.Mutable.Internal.Mutable m s, Data.Mutable.Internal.Mutable m a, Data.Mutable.Internal.Ref m s GHC.Types.~ Data.Mutable.Internal.GRef m s, Data.Generics.Product.Internal.HList.GIsList (Data.Mutable.Internal.GRef_ m (GHC.Generics.Rep s)) (Data.Mutable.Internal.GRef_ m (GHC.Generics.Rep s)) (Data.Mutable.Instances.MapRef m as) (Data.Mutable.Instances.MapRef m as), Data.Generics.Product.Internal.HList.GIsList (GHC.Generics.Rep s) (GHC.Generics.Rep s) as as, Data.Generics.Product.Internal.HList.ListTuple a a as as, Data.Generics.Product.Internal.HList.ListTuple b b (Data.Mutable.Instances.MapRef m as) (Data.Mutable.Instances.MapRef m as), Data.Mutable.Internal.Ref m a GHC.Types.~ b) => Data.Mutable.Parts.TupleMut m s a instance (Data.Mutable.Internal.Mutable m s, Data.Mutable.Internal.Mutable m a, Data.Mutable.Internal.Ref m s GHC.Types.~ Data.Mutable.Internal.GRef m s, Data.Generics.Product.Internal.GLens.GLens' (Data.Mutable.Parts.HasTotalFieldPSym fld) (Data.Mutable.Internal.GRef_ m (GHC.Generics.Rep s)) (Data.Mutable.Internal.Ref m a), Data.Generics.Product.Fields.HasField' fld s a) => Data.Mutable.Parts.FieldMut fld m s a instance (Data.Mutable.Internal.Mutable m (z Data.Vinyl.Functor.Identity), Data.Mutable.Internal.Ref m (z Data.Vinyl.Functor.Identity) GHC.Types.~ z (Data.Mutable.Internal.RefFor m)) => Data.Mutable.Parts.HKDMutParts m z (GHC.Generics.K1 i (Data.Mutable.Internal.RefFor m c)) (GHC.Generics.K1 i (Data.Mutable.Parts.MutPart m (z Data.Vinyl.Functor.Identity) c)) instance (Data.Mutable.Internal.Mutable m (z Data.Vinyl.Functor.Identity), Data.Mutable.Internal.Ref m (z Data.Vinyl.Functor.Identity) GHC.Types.~ z (Data.Mutable.Internal.RefFor m)) => Data.Mutable.Parts.HKDMutParts m z GHC.Generics.U1 GHC.Generics.U1 instance (Data.Mutable.Internal.Mutable m (z Data.Vinyl.Functor.Identity), Data.Mutable.Internal.Ref m (z Data.Vinyl.Functor.Identity) GHC.Types.~ z (Data.Mutable.Internal.RefFor m), (TypeError ...)) => Data.Mutable.Parts.HKDMutParts m z GHC.Generics.V1 GHC.Generics.V1 instance forall k (m :: * -> *) (z :: (* -> *) -> *) (i :: k -> *) (o :: k -> *) a (b :: GHC.Generics.Meta). Data.Mutable.Parts.HKDMutParts m z i o => Data.Mutable.Parts.HKDMutParts m z (GHC.Generics.M1 a b i) (GHC.Generics.M1 a b o) instance forall k (m :: * -> *) (z :: (* -> *) -> *) (i :: k -> *) (o :: k -> *) (i' :: k -> *) (o' :: k -> *). (Data.Mutable.Parts.HKDMutParts m z i o, Data.Mutable.Parts.HKDMutParts m z i' o') => Data.Mutable.Parts.HKDMutParts m z (i GHC.Generics.:*: i') (o GHC.Generics.:*: o') instance forall k (m :: * -> *) (z :: (* -> *) -> *) (i :: k -> *) (i' :: k -> *) (o :: k -> *). (Data.Mutable.Internal.Mutable m (z Data.Vinyl.Functor.Identity), Data.Mutable.Internal.Ref m (z Data.Vinyl.Functor.Identity) GHC.Types.~ z (Data.Mutable.Internal.RefFor m), (TypeError ...)) => Data.Mutable.Parts.HKDMutParts m z (i GHC.Generics.:+: i') o instance Control.Category.Category (Data.Mutable.Parts.MutPart m) instance Data.Vinyl.XRec.IsoHKD (Data.Mutable.Parts.MutPart m s) a -- | Main entrypoint of the package. Abstract over different types for -- piecewise-mutable references of values. -- -- See https://mutable.jle.im/ for a comprehensive introduction. module Data.Mutable -- | An instance of Mutable m a means that a can -- be stored a mutable reference in monad m. -- -- The associated type Ref m a links any a to -- the type of its canonical mutable version. -- -- The benefit of this typeclass, instead of just using -- IORef or MutVar or specific mutable versions like -- Vector and MVector, is two-fold: -- --
instance (Mutable m a, Mutable m b) => -- Mutable m (a, b)If a and b are -- piecwise-mutable, then the instance here will appropriately utilize -- that fact.
-- data TwoVectors = TV
-- { tvInt :: Vector Int
-- , tvDouble :: Vector Double
-- }
-- deriving Generic
--
-- instance Mutable m TwoVectors where
-- type Ref m TwoVectors = GRef m TwoVectors
--
--
-- Then now we get:
--
-- -- thawRef :: TwoVectors -> m (GRef m TwoVectors) -- freezeRef :: GRef m TwoVectors -> m TwoVectors ---- -- And GRef m TwoVectors is now a piecewise-mutable -- reference storing each part in a way that can be modified separately -- (for example, with tools from Data.Mutable.Parts). It does this -- by internally allocating two MVectors. If the two vectors are -- large, this can be much more efficient to modify (if you are modifying -- several times) than by just doing alterations on -- TwoVectors. It is also much better for large vectors if you -- plan on modifying only a single item in the vector. -- -- If you are using the "higher-kinded" data pattern, a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/, -- then we can also do: -- --
-- data TwoVectors f = TV
-- { tvInt :: HKD f (Vector Int)
-- , tvDouble :: HKD f (Vector Double)
-- }
-- deriving Generic
--
-- instance Mutable (TwoVectors Identity) where
-- type Ref (TwoVectors Identity) = TwoVectors (RefFor m)
--
--
-- And now your mutable ref is literally going to be a product of the
-- components
--
-- -- ghci> tvr@(TV is ds) <- thawRef (TV xs ys) -- ghci> :t tvr -- TV (RefFor IO) -- ghci> :t is -- MVector RealWorld Int -- ghci> :t ds -- MVector RealWorld Double ---- -- So thawRef will actually just get you the same record type but -- with the mutable versions of each field. If you modify the mutable -- fields, and then later freezeRef the whole thing, the resulting -- frozen value will incorporate all of the changes to the individual -- fields. -- -- In addition, there are a few more "automatically derived" instances -- you can get by picking Ref: -- --
-- -- Make a mutable version for any newtype wrapper, using the Mutable -- -- of the underlying type -- newtype MyType = MT (Vector Double) -- -- type Ref m MyType = CoerceRef m MyType (Vector Double) -- -- -- Make a mutable version of any container, where the items are all -- -- mutable references. -- data MyContainer a = MC a a a a -- deriving (Functor, Foldable, Traversable) -- -- type Ref m (MyContainer a) = TraverseRef m MyContainer a ---- -- See https://mutable.jle.im/02-mutable-and-ref.html for more -- information on this typeclass and how to define instances -- automatically, and also -- --
-- type Ref m (Vector a) = MVector (PrimState m) a
--
--
-- This means that using thawRef on a Vector will give you
-- an MVector, using freezeRef on a Vector will give
-- you a Vector, etc.
--
--
-- thawRef
-- :: (PrimMonad m, s ~ PrimState m)
-- => Vector a
-- -> m (Vector s a)
--
-- freezeRef
-- :: (PrimMonad m, s ~ PrimState m)
-- => Vector s a
-- -> m (Vector a)
--
-- copyRef
-- :: (PrimMonad m, s ~ PrimState m)
-- => Vector s a
-- -> Vector a
-- -> m ()
--
--
-- This associated type must be unique for a, so no two types
-- a can have the same Ref m a. This makes type
-- inference a lot more useful: if you use freezeRef on an
-- MVector, for instance, the return type will be inferred to be
-- Vector.
--
-- The default instance is just a plain old MutVar
-- containing the type. This is a valid instance, but it treats the
-- entire type "wholesale" --- it is basically using it as a non-mutable
-- type. You won't get any of the performance benefits of piecewise
-- mutation from it, but it is useful as a base case for non-composite
-- types like Int.
--
-- There are some built-in alternative options for user-defined ADTs with
-- Generic instances:
--
--
-- -- Works for all Generic instances, preserves piecewise mutation
-- -- for products
-- type Ref m a = GRef m a
--
--
-- If you just set up a blank instance, the implementations of
-- thawRef, freezeRef, and copyRef will be inferred
-- using DefaultMutable.
--
--
-- data MyType
--
-- -- The default setup is OK
-- instance Mutable m MyType
--
-- -- This is equivalent to the above
-- instance Mutable m MyType
-- type Ref m MyType = MutVar (PrimState m) MyType
--
-- -- any Generic instance
-- data MyType = MyType { mtInt :: Int, mtDouble :: Double }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- See https://mutable.jle.im/02-mutable-and-ref.html for more
-- information on this type family and how to define instances
-- automatically.
type family Ref m a = (v :: Type) | v -> a;
type Ref m a = MutVar (PrimState m) a;
}
-- | Thaw a pure/persistent value into its mutable version, which
-- can be manipulated using modifyRef or other methods specific
-- for that type (like read).
--
-- Returns the Ref instance, so, for example, for Vector:
--
-- -- thawRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector a -- -> m (Vector s a) ---- -- For non-composite (like Int), this is often called the "new -- var" function, like newIORef / newSTRef / -- newMutVar etc. thawRef :: Mutable m a => a -> m (Ref m a) -- | Freeze a mutable value into its pure/persistent version. -- -- Takes a Ref instance, but type inference will be able to infer -- the pure value's type because Ref is injective. -- -- For example, for Vector: -- --
-- freezeRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector s a -- -> m (Vector a) ---- -- For non-composite (like Int), this is often called the "read -- var" function, like readIORef / readSTRef / -- readMutVar etc. freezeRef :: Mutable m a => Ref m a -> m a -- | Overwrite a mutable value by provivding a pure/persistent value. -- copyRef -- -- Returns the Ref and the value, so, for example, for -- Vector: -- --
-- copyRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector s a -- -> Vector a -- -> m () ---- -- Note that if a is a composite type (with an appropriate -- composite reference), this will be done "piecewise": it'll write to -- each mutable component separately. -- -- For non-composite (like Int), this is often called the "write -- var" function, like writeIORef / writeSTRef / -- writeMutVar etc. copyRef :: Mutable m a => Ref m a -> a -> m () -- | Deep Copy-move a mutable reference on top of another, overwriting the -- second one. -- -- For non-composite types, this is the same as a thawRef and a -- copyRef. For composite types this can be more effficient -- because the copying is done piecewise, so the intermediate pure value -- is never created. moveRef :: Mutable m a => Ref m a -> Ref m a -> m () -- | Create a deep copy of a mutable reference, allocated to a separate -- independent reference. -- -- For non-composite types, this is the same as a thawRef and a -- freezeRef. For composite types this can be more effficient -- because the cloning is done piecewise, so the intermediate pure value -- is never created. cloneRef :: Mutable m a => Ref m a -> m (Ref m a) -- | A non-copying version of thawRef that can be more efficient for -- types where the mutable representation is the same as the immutable -- one (like Vector). -- -- This is safe as long as you never again use the original pure value, -- since it can potentially directly mutate it. unsafeThawRef :: Mutable m a => a -> m (Ref m a) -- | A non-copying version of freezeRef that can be more efficient -- for types where the mutable representation is the same as the -- immutable one (like Vector). -- -- This is safe as long as you never again modify the mutable reference, -- since it can potentially directly mutate the frozen value magically. unsafeFreezeRef :: Mutable m a => Ref m a -> m a -- | Thaw a pure/persistent value into its mutable version, which -- can be manipulated using modifyRef or other methods specific -- for that type (like read). -- -- Returns the Ref instance, so, for example, for Vector: -- --
-- thawRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector a -- -> m (Vector s a) ---- -- For non-composite (like Int), this is often called the "new -- var" function, like newIORef / newSTRef / -- newMutVar etc. thawRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => a -> m (Ref m a) -- | Freeze a mutable value into its pure/persistent version. -- -- Takes a Ref instance, but type inference will be able to infer -- the pure value's type because Ref is injective. -- -- For example, for Vector: -- --
-- freezeRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector s a -- -> m (Vector a) ---- -- For non-composite (like Int), this is often called the "read -- var" function, like readIORef / readSTRef / -- readMutVar etc. freezeRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => Ref m a -> m a -- | Overwrite a mutable value by provivding a pure/persistent value. -- copyRef -- -- Returns the Ref and the value, so, for example, for -- Vector: -- --
-- copyRef -- :: (PrimMonad m, s ~ PrimState m) -- => Vector s a -- -> Vector a -- -> m () ---- -- Note that if a is a composite type (with an appropriate -- composite reference), this will be done "piecewise": it'll write to -- each mutable component separately. -- -- For non-composite (like Int), this is often called the "write -- var" function, like writeIORef / writeSTRef / -- writeMutVar etc. copyRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => Ref m a -> a -> m () -- | Deep Copy-move a mutable reference on top of another, overwriting the -- second one. -- -- For non-composite types, this is the same as a thawRef and a -- copyRef. For composite types this can be more effficient -- because the copying is done piecewise, so the intermediate pure value -- is never created. moveRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => Ref m a -> Ref m a -> m () -- | Create a deep copy of a mutable reference, allocated to a separate -- independent reference. -- -- For non-composite types, this is the same as a thawRef and a -- freezeRef. For composite types this can be more effficient -- because the cloning is done piecewise, so the intermediate pure value -- is never created. cloneRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => Ref m a -> m (Ref m a) -- | A non-copying version of thawRef that can be more efficient for -- types where the mutable representation is the same as the immutable -- one (like Vector). -- -- This is safe as long as you never again use the original pure value, -- since it can potentially directly mutate it. unsafeThawRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => a -> m (Ref m a) -- | A non-copying version of freezeRef that can be more efficient -- for types where the mutable representation is the same as the -- immutable one (like Vector). -- -- This is safe as long as you never again modify the mutable reference, -- since it can potentially directly mutate the frozen value magically. unsafeFreezeRef :: (Mutable m a, DefaultMutable m a (Ref m a)) => Ref m a -> m a -- | Apply a pure function on an immutable value onto a value stored in a -- mutable reference. modifyRef :: Mutable m a => Ref m a -> (a -> a) -> m () -- | modifyRef, but forces the result before storing it back in the -- reference. modifyRef' :: Mutable m a => Ref m a -> (a -> a) -> m () -- | Apply a pure function on an immutable value onto a value stored in a -- mutable reference, returning a result value from that function. updateRef :: Mutable m a => Ref m a -> (a -> (a, b)) -> m b -- | updateRef, but forces the updated value before storing it back -- in the reference. updateRef' :: Mutable m a => Ref m a -> (a -> (a, b)) -> m b -- | A handy newtype wrapper that allows you to partially apply Ref. -- RefFor m a is the same as Ref m a, but -- can be partially applied. -- -- If used with HKD, you can treat this syntactically identically -- as a Ref m a. newtype RefFor m a RefFor :: Ref m a -> RefFor m a [getRefFor] :: RefFor m a -> Ref m a -- | The default implementations of thawRef, freezeRef, and -- copyRef dispatched for different choices of Ref. -- -- Basically, by specifying Ref, you get the rest of the instance -- for free. -- -- We have the default case: -- --
-- -- default, if you don't specify Ref -- instance Mutable m MyType -- -- -- the above is the same as: -- instance Mutable m MyType -- type Ref m MyType = MutVar (PrimState m) MyType ---- -- The case for any instance of Generic: -- --
-- instance Mutable m MyType -- type Ref m MyType = GRef m MyType ---- -- The case for the "higher-kinded data" pattern a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/: -- --
-- instance Mutable m (MyTypeF Identity) -- type Ref m (MyTypeF Identity) = MyTypeF (RefFor m) ---- -- The case for any newtype wrapper: -- --
-- newtype MyType = MT (Vector Double) -- -- instance Mutable m MyType where -- type Ref m MyType = CoerceRef m MyType (Vector Double) ---- -- And the case for any 'Traversable instance, where the items will all -- be mutable references: -- --
-- data MyContainer a = MC a a a a -- deriving (Functor, Foldable, Traversable) -- -- instance Mutable m a => Mutable m (MyContainer a) where -- type Ref m (MyContainer a) = TraverseRef m MyContainer a --class DefaultMutable m a r | r -> a -- | Automatically generate a piecewise mutable reference for any -- Generic instance. -- --
-- -- | any Generic instance
-- data MyType = MyType { mtInt :: Int, mtDouble :: Double }
-- deriving (Generic, Show)
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- -- ghci> r <- thawRef (MyType 3 4.5) -- ghci> freezeRef r -- MyType 3 4.5 -- ghci> freezePart (fieldMut #mtInt) r -- 3 -- ghci> copyPart (fieldMut #mtDouble) 1.23 -- ghci> freezeRef r -- MyType 3 1.23 ---- -- Note that this is basically just a bunch of tupled refs for a product -- type. For a sum type (with multiple constructors), an extra layer of -- indirection is added to account for the dynamically changable shape. -- -- See Data.Mutable.Parts and Data.Mutable.Branches for -- nice ways to inspect and mutate the internals of this type (as -- demonstrated above). -- -- If the facilities in those modules are not adequate, you can also -- manually crack open GRef and work with the internals. Getting -- the type of unGRef @MyType should allow you to -- navigate what is going on, if you are familiar with -- GHC.Generics. However, ideally, you would never need to do -- this. data GRef m a -- | A MutVar behaves like a single-element mutable array associated -- with a primitive state token. data MutVar s a -- | A Ref that works by using the Mutable instance of an -- equivalent type. This is useful for newtype wrappers, so you can use -- the underlying data type's Mutable instance. -- --
-- newtype MyVec = MyVec (Vector Double) -- -- instance Mutable m MyVec where -- type Ref m MyVec = CoerceRef m s (Vector Double) ---- -- The Ref m MyVec uses the a MVector Double -- under the hood. -- -- It's essentially a special case of GRef for newtypes. newtype CoerceRef m s a CoerceRef :: Ref m a -> CoerceRef m s a [getCoerceRef] :: CoerceRef m s a -> Ref m a -- | A Ref that works for any instance of Traversable, by -- using the fields of the Traversable instance to purely -- store mutable references. -- -- Note that this really only makes complete sense if the -- Traversable is fixed-size, or you never modify the length of -- the traversable as you use it as a reference. -- -- If you do modify the length, copying and modifying semantics -- can be a bit funky: -- --
-- ghci> r <- thawTraverse [1..10] -- ghci> copyTraverse r [0,0,0,0] -- ghci> freezeTraverse r -- [0,0,0,0,5,6,7,8,9,10] -- ghci> copyTraverse r [20..50] -- ghci> freezeTraverse r -- [20,21,22,23,24,25,26,27,28,29] --newtype TraverseRef m f a TraverseRef :: f (Ref m a) -> TraverseRef m f a [getTraverseRef] :: TraverseRef m f a -> f (Ref m a) -- | A Ref for instances of GMutable, which are the -- GHC.Generics combinators. newtype GMutableRef m f a GMutableRef :: GRef_ m f a -> GMutableRef m f a [getGMutableRef] :: GMutableRef m f a -> GRef_ m f a -- | The mutable reference of the HList type from generic-lens. data HListRef :: (Type -> Type) -> [Type] -> Type [NilRef] :: HListRef m '[] [:!>] :: Ref m a -> HListRef m as -> HListRef m (a : as) infixr 5 :!> -- | Newtype wrapper that can provide any type with a Mutable -- instance, giving it a "non-piecewise" instance. Can be useful for -- avoiding orphan instances yet still utilizing auto-deriving features, -- or for overwriting the Mutable instance of other instances. -- -- For example, let's say you want to auto-derive an instance for your -- data type: -- --
-- data MyType = MT Int Double OtherType -- deriving Generic ---- -- This is possible if all of MyTypes fields have Mutable -- instances. However, let's say OtherType comes from an -- external library that you don't have control over, and so you cannot -- give it a Mutable instance without incurring an orphan -- instance. -- -- One solution is to wrap it in VarMut: -- --
-- data MyType = MT Int Double (VarMut OtherType) -- deriving Generic ---- -- This can then be auto-derived: -- --
-- instance Mutable m MyType where -- type Ref m MyType = GRef m MyType ---- -- It can also be used to override a Mutable instance. For -- example, even if the Mutable instance of SomeType is -- piecewise-mutable, the Mutable instance of VarMut -- SomeType will be not be piecewise. -- -- For example, the Mutable instance for String is a -- mutable linked list, but it might be more efficient to treat it as an -- atomic value to update all at once. You can use VarMut -- String to get that Mutable instance. newtype VarMut a VarMut :: a -> VarMut a [getVarMut] :: VarMut a -> a -- | Similar to VarMut, this allows you to overwrite the normal -- Mutable instance of a type to utilize a coercible type's -- Mutable instance instead of its normal instance. It's also -- useful to provide an instance for an externally defined type without -- incurring orphan instances. -- -- For example, if an external library provides -- --
-- newtype DoubleVec = DV (Vector Double) ---- -- and you want to use it following Vectors Mutable -- instance (via MVector), but you don't want to write an orphan -- instance like -- --
-- instance Mutable m DoubleVec where -- type Ref m DoubleVec = CoerceRef m DoubleVec (Vector Double) ---- -- then you can instead use CoerceMut DoubleVec (Vector -- Double) as the data type. This wrapped type does use the -- inderlying Mutable insatnce for Vector. newtype CoerceMut s a CoerceMut :: s -> CoerceMut s a [getCoerceMut] :: CoerceMut s a -> s -- | Similar to VarMut, this allows you to overwrite the normal -- Mutable instance for a type to utilize its Traversable -- instance instead of its normal instance. It's also useful to provide -- an instance for an externally defined type without incurring orphan -- instances. -- -- For example, the instance of Mutable (TraverseMut [] -- a) is a normal list of mutable references, instead of a full-on -- mutable linked list. newtype TraverseMut f a TraverseMut :: f a -> TraverseMut f a [getTraverseMut] :: TraverseMut f a -> f a -- | Similar to VarMut, this allows you to overwrite the normal -- Mutable instance of a type to make it immutable. -- -- For example, let's say you have a type, with the automatically derived -- generic instance of Mutable: -- --
-- data MyType = MT
-- { mtX :: Int
-- , mtY :: Vector Double
-- , mtZ :: String
-- }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- This basically uses three mutable references: the Int, the
-- Vector Double, and the String. However, you
-- might want the Mutable instance of MyType to be
-- immutable String field, and so it cannot be updated at
-- all even when thawed. To do that, you can instead have:
--
--
-- data MyType = MT
-- { mtX :: Int
-- , mtY :: Vector Double
-- , mtZ :: Immutable String
-- }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- which has that behavior. The Int and the Vector will be
-- mutable within Ref m MyType, but not the
-- String.
newtype Immutable a
Immutable :: a -> Immutable a
[getImmutable] :: Immutable a -> a
-- | A MutPart m s a is a way to "zoom into" an a,
-- as a part of a mutable reference on s. This allows you to
-- only modify a single a part of the s, without
-- touching the rest. It's spiritually similar to a Lens' s a.
--
-- If MutBranch is for sum types, then MutPart is for
-- product types.
--
-- See https://mutable.jle.im/05-mutable-parts.html for an
-- introduction to this type.
--
-- An example that is commonly found in the ecosystem is something like
-- (flipped) write :: Int -> MVector s a -> a -> m
-- () from Data.Vector.Mutable --- write 3 ::
-- MVector s a -> a -> m (), for instance, lets you
-- modify a specific part of the vector without touching the rest.
--
-- You would use a MutPart using freezePart,
-- copyPart, modifyPart, etc.
--
-- For non-composite types, there won't really be any meaningful values.
-- However, we have them for many composite types. For example, for
-- tuples:
--
-- -- mutFst :: MutPart m (a, b) a -- mutSnd :: MutPart m (a, b) b ---- --
-- ghci> r <- thawRef (2, 4) -- ghci> copyPart mutFst r 100 -- ghci> freezeRef r -- (100, 4) ---- -- If you are using GRef as an automatically-defined mutable -- reference, then the easiest way to create these for your mutable types -- are with fieldMut and posMut. -- -- If you are using the "Higher-kinded data" pattern, then there's an -- easy way to generate a MutPart for every single field, if you -- have a product type --- see hkdMutParts for more information. newtype MutPart m s a MutPart :: (Ref m s -> Ref m a) -> MutPart m s a [getMutPart] :: MutPart m s a -> Ref m s -> Ref m a -- | Using a MutPart, perform a function on a Ref m -- s as if you had a Ref m a. withPart :: MutPart m s a -> Ref m s -> (Ref m a -> m r) -> m r -- | With a MutPart, read out a specific part of a Ref. freezePart :: Mutable m a => MutPart m s a -> Ref m s -> m a -- | With a MutPart, overwrite into a specific part of a Ref. copyPart :: Mutable m a => MutPart m s a -> Ref m s -> a -> m () -- | With a MutPart, copy a Ref containing a subvalue into a -- specific part of a larger Ref. -- --
-- data MyType = MT { mtInt :: Int, mtDouble :: Double }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- -- ghci> x <- thawRef $ MyType 3 4.5 -- ghci> y <- thawRef $ 100 -- ghci> movePartInto (fieldMut #mtInt) x y -- ghci> freezeRef x -- MyType 100 4.5 --movePartInto :: Mutable m a => MutPart m s a -> Ref m s -> Ref m a -> m () -- | With a MutPart, copy a specific part of a larger Ref -- into a Ref of the smaller subvalue value. -- --
-- data MyType = MT { mtInt :: Int, mtDouble :: Double }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- -- ghci> x <- thawRef $ MyType 3 4.5 -- ghci> y <- thawRef $ 100 -- ghci> movePartOver (fieldMut #mtInt) y x -- ghci> freezeRef y -- 3 --movePartOver :: Mutable m a => MutPart m s a -> Ref m a -> Ref m s -> m () -- | With a MutPart, copy a specific part of a large Ref into -- that same part in another large Ref. -- --
-- data MyType = MT { mtInt :: Int, mtDouble :: Double }
-- deriving Generic
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- -- ghci> x <- thawRef $ MyType 3 4.5 -- ghci> y <- thawRef $ MyType 100 12.34 -- ghci> movePartWithin (fieldMut #mtInt) x y -- ghci> freezeRef x -- MyType 100 4.5 --movePartWithin :: Mutable m a => MutPart m s a -> Ref m s -> Ref m s -> m () -- | Clone out a subvalue of a larger Ref. clonePart :: Mutable m a => MutPart m s a -> Ref m s -> m (Ref m a) -- | A non-copying version of unsafeFreezeRef that can be more -- efficient for types where the mutable representation is the same as -- the immutable one (like Vector). -- -- This is safe as long as you never again modify the mutable reference, -- since it can potentially directly mutate the frozen value magically. unsafeFreezePart :: Mutable m a => MutPart m s a -> Ref m s -> m a -- | With a MutPart, modify a specific part of a Ref with a -- pure function. modifyPart :: Mutable m a => MutPart m s a -> Ref m s -> (a -> a) -> m () -- | modifyPart, but forces the result before storing it back in the -- reference. modifyPart' :: Mutable m a => MutPart m s a -> Ref m s -> (a -> a) -> m () -- | updateRef, under a MutPart to only modify a specific -- part of a Ref. updatePart :: Mutable m a => MutPart m s a -> Ref m s -> (a -> (a, b)) -> m b -- | updatePart, but forces the result before storing it back in the -- reference. updatePart' :: Mutable m a => MutPart m s a -> Ref m s -> (a -> (a, b)) -> m b -- | Create a MutPart for a field name. Should work for any type -- with one constructor whose mutable reference is GRef. See -- fieldMut for usage directions. -- -- Mostly leverages the power of Data.Generics.Product.Fields. class (Mutable m s, Mutable m a) => FieldMut (fld :: Symbol) m s a | fld s -> a -- | Create a MutPart for a field name. Should work for any type -- with one constructor whose mutable reference is GRef. -- -- Is meant to be used with OverloadedLabels: -- --
-- data MyType = MyType { mtInt :: Int, mtDouble :: Double }
-- deriving (Generic, Show)
--
-- instance Mutable m MyType where
-- type Ref m MyType = GRef m MyType
--
--
-- -- ghci> r <- thawRef (MyType 3 4.5) -- ghci> freezePart (fieldMut #mtInt) r -- 3 -- ghci> copyPart (fieldMut #mtDouble) 1.23 -- ghci> freezeRef r -- MyType 3 1.23 ---- -- However, you can use it without OverloadedLabels by using Label -- with TypeApplications: -- --
-- ghci> freezePart (fieldMut (Label @"mtInt")) r -- 3 ---- -- This and posMut are the main ways to generate a MutPart -- for a type whose mutable reference is GRef. Note that because -- all of the lookups are done at compile-time, fieldMut and -- posMut have more or less identical performance characteristics. fieldMut :: FieldMut fld m s a => Label fld -> MutPart m s a -- | A helpful wrapper over withPart (fieldMut -- #blah). Create a fieldMut and directly use it. withField :: FieldMut fld m s a => Label fld -> Ref m s -> (Ref m a -> m b) -> m b -- | A helpful wrapper around getMutPart (fieldMut -- #blah). Directly use a fieldMut to access a mutable field. mutField :: forall fld m s a. FieldMut fld m s a => Label fld -> Ref m s -> Ref m a -- | Proxy for label type data Label (a :: Symbol) Label :: Label (a :: Symbol) -- | Create a MutPart for a position in a product type. Should work -- for any type with one constructor whose mutable reference is -- GRef. See posMut for usage directions. -- -- Mostly leverages the power of Data.Generics.Product.Positions. class (Mutable m s, Mutable m a) => PosMut (i :: Nat) m s a | i s -> a -- | Create a MutPart for a position in a product type. Should work -- for any type with one constructor whose mutable reference is -- GRef. -- -- Meant to be used with TypeApplications: -- --
-- data MyType = MyType Int Double -- deriving (Generic, Show) -- -- instance Mutable m MyType where -- type Ref m MyType = GRef m MyType ---- --
-- ghci> r <- thawRef (MyType 3 4.5) -- ghci> freezePart (posMut @1) r -- 3 -- ghci> copyPart (posMut @2) 1.23 -- ghci> freezeRef r -- MyType 3 1.23 ---- -- This and fieldMut are the main ways to generate a -- MutPart for a type whose mutable reference is GRef. Note -- that because all of the lookups are done at compile-time, -- posMut and fieldMut have more or less identical -- performance characteristics. posMut :: PosMut i m s a => MutPart m s a -- | A helpful wrapper over withPart (posMut @n). -- Create a posMut and directly use it. withPos :: forall i m s a r. PosMut i m s a => Ref m s -> (Ref m a -> m r) -> m r -- | A helpful wrapper around getMutPart (posMut -- @n). Directly use a posMut to access a mutable field. mutPos :: forall i m s a. PosMut i m s a => Ref m s -> Ref m a -- | Create a MutPart splitting out a product type into a tuple of -- refs for every field in that product type. Should work for any type -- with one constructor whose mutable reference is GRef. See -- tupleMut for usage directions. -- -- Mostly leverages the power of Data.Generics.Product.HList. class (Mutable m s, Mutable m a) => TupleMut m s a | s -> a -- | Create a MutPart splitting out a product type into a tuple of -- refs for every field in that product type. Should work for any type -- with one constructor whose mutable reference is GRef. -- -- Probably most easily used using withTuple: -- --
-- data MyType = MyType Int Double -- deriving (Generic, Show) -- -- instance Mutable m MyType where -- type Ref m MyType = GRef m MyType ---- -- Now there is an instance of TupleMut m MyType (Int, -- Double). -- --
-- ghci> r <- thawRef (MyType 3 4.5) -- ghci> withTuple r $ (rI, rD) -> do -- .. modifyRef rI negate -- .. modifyRef rD (* 2) -- ghci> freezeRef r -- MyType (-3) 9 ---- -- As can be seen, within the lambda, we can get access to every mutable -- reference inside a MyType reference. -- -- Performance-wise, this appears to be faster than fieldMut and -- posMut when using a single reference, but slower if using all -- references. tupleMut :: TupleMut m s a => MutPart m s a -- | A helpful wrapper over withPart tupleMut. -- Directly operate on the items in the data type, getting the references -- as a tuple. See tupleMut for more details on when this should -- work. -- --
-- data MyType = MyType Int Double -- deriving (Generic, Show) -- -- instance Mutable m MyType where -- type Ref m MyType = GRef m MyType ---- --
-- ghci> r <- thawRef (MyType 3 4.5) -- ghci> withTuple r $ (rI, rD) -> do -- .. modifyRef rI negate -- .. modifyRef rD (* 2) -- ghci> freezeRef r -- MyType (-3) 9 --withTuple :: TupleMut m s a => Ref m s -> (Ref m a -> m r) -> m r -- | If you are using the "higher-kinded data" pattern, a la -- https://reasonablypolymorphic.com/blog/higher-kinded-data/, and -- you have the appropriate instance for Ref, then you can use -- this to generate a MutPart for every field, if you have a type -- with only one constructor. -- --
-- data MyTypeF f = MT
-- { mtInt :: f Int
-- , mtDouble :: f Double
-- }
-- deriving Generic
--
-- instance Mutable (MyTypeF Identity) where
-- type Ref (MyTypeF Identity) = MyTypeF (RefFor m)
--
-- mx :: MutPart m (MyTypeF Identity) (Vector Int)
-- my :: MutPart m (MyTypeF Identity) (Vector Double)
-- MT mx my = hkdMutParts @MyTypeF
--
--
-- -- ghci> r <- thawRef (MT 3 4.5) -- ghci> freezePart mx r -- 3 -- ghci> copyPart (mtDouble (hkdMutParts @MyTypeF)) r 12.3 -- ghci> freezeRef r -- MT 3 12.3 ---- -- Performance-wise, this is about equivalent to fieldMut and -- posMut for the most part, so the main advantage would be purely -- syntactical. If performance is an issue, you should benchmark all the -- different ways just to be sure. As a general rule, it seems like deep -- nested accesses are faster with composition of fieldMut and -- posMut, but immediate shallow access is often faster with -- hkdMutParts...but this probably does vary on a case-by-case -- basis. hkdMutParts :: forall z m. (Generic (z (RefFor m)), Generic (z (MutPart m (z Identity))), HKDMutParts m z (Rep (z (RefFor m))) (Rep (z (MutPart m (z Identity))))) => z (MutPart m (z Identity)) -- | Typeclass used to implement hkdMutParts. See documentation of -- hkdMutParts for more information. class (Mutable m (z Identity), Ref m (z Identity) ~ z (RefFor m)) => HKDMutParts m z i o -- | MutPart into the first field of a tuple reference. mutFst :: MutPart m (a, b) a -- | MutPart into the second field of a tuple reference. mutSnd :: MutPart m (a, b) b -- | A MutPart for a field in a vinyl Rec, automatically -- generated as the first field with a matching type. This is polymorphic -- to work over both Rec and ARec. -- --
-- ghci> r <- thawRef $ [1,2,3] :& [True, False] :& RNil -- ghci> modifyPart (mutRec @Bool) r reverse -- ghci> freezeRef r -- [1,2,3] :& [False, True] :& RNil --mutRec :: forall a as f rec m. (Ref m (rec f as) ~ rec (RecRef m f) as, RecElem rec a a as as (RIndex a as), RecElemFCtx rec (RecRef m f)) => MutPart m (rec f as) (f a) -- | A MutPart to get into a CoerceRef. coerceRef :: Ref m s ~ CoerceRef m s a => MutPart m s a -- | Handy wrapper over getMutPart coerceRef. withCoerceRef :: CoerceRef m s a -> (Ref m a -> m r) -> m r -- | A MutBranch m s a represents the information that -- s could potentially be an a. Similar in spirit to a -- Prism' s a. -- -- MutBranch m s a means that a is one potential -- option that s could be in, or that s is a sum type -- and a is one of the branches/constructors. -- -- See https://mutable.jle.im/06-mutable-branches.html for an -- introduction to this module. -- -- If MutPart is for product types, then MutBranch is for -- sum types. -- -- In this case, "branch" means "potential option". For example, the -- branches of Either are Left and Right. -- -- The simplest way to make these is by using constrMB. For -- instance, to get the two branches of an Either: -- --
-- constrMB #_Left :: MutBranch m (Either a b) a -- constrMB #_Right :: MutBranch m (Either a b) b ---- --
-- ghci> r <- thawRef (Left 10) -- ghci> freezeBranch (constrMB #_Left) r -- Just 10 -- ghci> freezeBranch (constrMB #_Right) r -- Nothing ---- -- It uses OverloadedLabels, but requires an underscore before the -- constructor name due to limitations in the extension. -- -- One nice way to use these is with withBranch_: -- --
-- ghci> r <- thawRef (Just 10) -- ghci> withBranch_ (constrMB #_Just) $ i -> -- i is an Int ref -- .. modifyRef i (+ 1) -- ghci> freezeRef r -- Just 11 ---- --
-- ghci> r <- thawRef Nothing -- ghci> withBranch_ (constrMB #_Just) $ i -> -- i is an Int ref -- .. modifyRef i (+ 1) -- ghci> freezeRef r -- Nothing ---- -- Perhaps the most useful usage of this abstraction is for recursive -- data types. -- --
-- data List a = Nil | Cons a (List a) -- deriving Generic -- -- instance Mutable m a => Mutable m (List a) where -- type Ref m (List a) = GRef m (List a) ---- -- GRef m (List a) is now a mutable linked list! Once we -- make the MutBranch for the nil and cons cases: -- --
-- nilBranch :: MutBranch m (List a) () -- nilBranch = constrMB #_Nil -- -- consBranch :: MutBranch m (List a) (a, List a) -- consBranch = constrMB #_Cons ---- -- Here is a function to check if a linked list is currently empty: -- --
-- isEmpty -- :: (PrimMonad m, Mutable m a) -- => Ref m (List a) -- -> m Bool -- isEmpty = hasBranch nilBranch ---- -- Here is one to "pop" a mutable linked list, giving us the first value -- and shifting the rest of the list up. -- --
-- popStack -- :: (PrimMonad m, Mutable m a) -- => Ref m (List a) -- -> m (Maybe a) -- popStack r = do -- c <- projectBranch consBranch r -- case c of -- Nothing -> pure Nothing -- Just (x, xs) -> do -- moveRef r xs -- Just $ freezeRef x ---- -- And here is a function to concatenate a second linked list to the end -- of a first one. -- --
-- concatLists -- :: (PrimMonad m, Mutable m a) -- => Ref m (List a) -- -> Ref m (List a) -- -> m () -- concatLists l1 l2 = do -- c <- projectBranch consBranch l1 -- case c of -- Nothing -> moveRef l1 l2 -- Just (_, xs) -> concatLists xs l2 --data MutBranch m s a MutBranch :: (Ref m s -> m (Maybe (Ref m a))) -> (Ref m a -> m (Ref m s)) -> MutBranch m s a -- | With a MutBranch, attempt to get the mutable contents of a -- branch of a mutable s, if possible. -- --
-- ghci> r <- thawRef (Left 10) -- ghci> s <- projectBranch (constrMB #_Left) r -- ghci> case s of Just s' -> freezeRef s' -- 10 ---- --
-- ghci> r <- thawRef (Right True) -- ghci> s <- projectBranch (constrMB #_Left) r -- ghci> case s of Nothing -> "it was Right" -- "it was Right" --[projectBranch] :: MutBranch m s a -> Ref m s -> m (Maybe (Ref m a)) -- | Embed an a ref as a part of a larger s ref. Note -- that this does not copy or clone: any mutations to the -- a ref will be reflected in the s ref, as long as the -- s ref maintains the reference. -- --
-- ghci> r <- thawRef 100 -- ghci> s <- embedBranch (constMB #_Left) r -- ghci> freezeRef s -- Left 100 -- ghci> modifyRef r (+ 1) -- ghci> freezeRef s -- Left 101 ---- -- Any mutations on s (as long as they keep the same branch) -- will also affect a: -- --
-- ghci> copyRef s (Left 0) -- ghci> freezeRef r -- 0 ---- -- However, "switching branches" on an Either ref will cause it to -- loose the original reference: -- --
-- ghci> copyRef s (Right True) -- ghci> copyRef s (Left 999) -- ghci> freezeRef r -- 0 --[embedBranch] :: MutBranch m s a -> Ref m a -> m (Ref m s) -- | With a MutBranch, thaw an a into a mutable s -- on that branch. -- --
-- ghci> r <- thawBranch (constrMB #_Left) 10 -- ghci> freezeRef r -- Left 10 --thawBranch :: Mutable m a => MutBranch m s a -> a -> m (Ref m s) -- | With a MutBranch, read out a specific a branch of an -- s, if it exists. -- --
-- ghci> r <- thawRef (Left 10) -- ghci> freezeBranch (constrMB #_Left) r -- Just 10 -- ghci> freezeBranch (constrMB #_Right) r -- Nothing --freezeBranch :: Mutable m a => MutBranch m s a -> Ref m s -> m (Maybe a) -- | With a MutBranch, overwrite an s as an a, on -- that branch. -- --
-- ghci> r <- thawRef (Left 10) -- ghci> s <- thawRef 100 -- ghci> moveBranch (constrMB #_Left) r s -- ghci> freezeRef r -- Left 100 -- ghci> t <- thawRef True -- ghci> moveBranch (constrMB #_Right) r t -- ghci> freezeRef r -- Right True --moveBranch :: Mutable m s => MutBranch m s a -> Ref m s -> Ref m a -> m () -- | With a MutBranch, set s to have the branch -- a. -- --
-- ghci> r <- thawRef (Left 10) -- ghci> copyBranch (constrMB #_Left) r 5678 -- ghci> freezeRef r -- Left 5678 -- ghci> copyBranch (constrMB #_Right) r True -- ghci> freezeRef r -- Right True --copyBranch :: (Mutable m s, Mutable m a) => MutBranch m s a -> Ref m s -> a -> m () -- | With a MutBranch, attempt to clone out a branch of a mutable -- s, if possible. -- --
-- ghci> r <- thawRef (Left 10) -- ghci> s <- cloneBranch (constrMB #_Left) -- ghci> case s of Just s' -> freezeRef s' -- 10 ---- --
-- ghci> r <- thawRef (Right True) -- ghci> s <- cloneBranch (constrMB #_Left) -- ghci> case s of Nothing -> "it was Right" -- "it was Right" --cloneBranch :: Mutable m a => MutBranch m s a -> Ref m s -> m (Maybe (Ref m a)) -- | Check if an s is currently a certain branch a. hasBranch :: Mutable m a => MutBranch m s a -> Ref m s -> m Bool -- | Check if an s is not currently a certain branch -- a. hasn'tBranch :: Mutable m a => MutBranch m s a -> Ref m s -> m Bool -- | A non-copying version of thawBranch that can be more efficient -- for types where the mutable representation is the same as the -- immutable one (like Vector). -- -- This is safe as long as you never again use the original pure value, -- since it can potentially directly mutate it. unsafeThawBranch :: Mutable m a => MutBranch m s a -> a -> m (Ref m s) -- | A non-copying version of freezeBranch that can be more -- efficient for types where the mutable representation is the same as -- the immutable one (like Vector). -- -- This is safe as long as you never again modify the mutable reference, -- since it can potentially directly mutate the frozen value magically. unsafeFreezeBranch :: Mutable m a => MutBranch m s a -> Ref m s -> m (Maybe a) -- | With a MutBranch, if an s is on the a branch, -- perform an action on the a reference and overwrite the -- s with the modified a. Returns the result of the -- action, if a was found. -- --
-- ghci> r <- thawRef (Just 10) -- ghci> withBranch_ (constrMB #_Just) $ i -> -- i is an Int ref -- .. modifyRef i (+ 1) -- ghci> freezeRef r -- Just 11 ---- --
-- ghci> r <- thawRef Nothing -- ghci> withBranch_ (constrMB #_Just) $ i -> -- i is an Int ref -- .. modifyRef i (+ 1) -- ghci> freezeRef r -- Nothing --withBranch :: Mutable m a => MutBranch m s a -> Ref m s -> (Ref m a -> m b) -> m (Maybe b) -- | withBranch, but discarding the returned value. withBranch_ :: Mutable m a => MutBranch m s a -> Ref m s -> (Ref m a -> m b) -> m () -- | With a MutBranch, run a pure function over a potential branch -- a of s. If s is not on that branch, leaves -- s unchanged. -- --
-- ghci> r <- thawRef (Just 10) -- ghci> modifyBranch (constrMB #_Just) r (+ 1) -- ghci> freezeRef r -- Just 11 ---- --
-- ghci> r <- thawRef Nothing -- ghci> modifyBranch (constrMB #_Just) r (+ 1) -- ghci> freezeRef r -- Nothing --modifyBranch :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> a) -> m () -- | modifyBranch, but forces the result before storing it back in -- the reference. modifyBranch' :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> a) -> m () -- | With a MutBranch, run a pure function over a potential branch -- a of s. The function returns the updated a -- and also an output value to observe. If s is not on that -- branch, leaves s unchanged. -- --
-- ghci> r <- thawRef (Just 10) -- ghci> updateBranch (constrMB #_Just) r $ i -> (i + 1, show i) -- Just "10" -- ghci> freezeRef r -- Just 11 ---- --
-- ghci> r <- thawRef Nothing -- ghci> updateBranch (constrMB #_Just) r $ i -> (i + 1, show i) -- Nothing -- ghci> freezeRef r -- Nothing --updateBranch :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> (a, b)) -> m (Maybe b) -- | updateBranch, but forces the result before storing it back in -- the reference. updateBranch' :: Mutable m a => MutBranch m s a -> Ref m s -> (a -> (a, b)) -> m (Maybe b) -- | Create a MutBranch for any data type with a Generic -- instance by specifying the constructor name using OverloadedLabels -- --
-- ghci> r <- thawRef (Left 10) -- ghci> freezeBranch (constrMB #_Left) r -- Just 10 -- ghci> freezeBranch (constrMB #_Right) r -- Nothing ---- -- Note that due to limitations in OverloadedLabels, you must prefix the -- constructor name with an undescore. -- -- There also isn't currently any way to utilize OverloadedLabels with -- operator identifiers, so using it with operator constructors (like -- : and []) requires explicit TypeApplications: -- --
-- -- | MutBranch focusing on the cons case of a list -- consMB :: (PrimMonad m, Mutable m a) => MutBranch m [a] (a, [a]) -- consMB = constrMB (CLabel @":") --constrMB :: forall ctor m s a. (Ref m s ~ GRef m s, GMutBranchConstructor ctor m (Rep s) a) => CLabel ctor -> MutBranch m s a -- | A version of Label that removes an underscore at the beginning -- when used with -XOverloadedLabels. Used to specify constructors, since -- labels are currently not able to start with capital letters. data CLabel (ctor :: Symbol) CLabel :: CLabel (ctor :: Symbol) -- | Typeclass powering constrMB using GHC Generics. -- -- Heavily inspired by Data.Generics.Sum.Constructors. class (GMutable m f, Mutable m a) => GMutBranchConstructor (ctor :: Symbol) m f a | ctor f -> a -- | Useful type family to Ref m over every item in a -- type-level list -- --
-- ghci> :kind! MapRef IO '[Int, V.Vector Double] -- '[ MutVar RealWorld Int, MVector RealWorld Double ] --type family MapRef m as -- | MutBranch focusing on the nil case of a list nilMB :: (PrimMonad m, Mutable m a) => MutBranch m [a] () -- | MutBranch focusing on the cons case of a list consMB :: (PrimMonad m, Mutable m a) => MutBranch m [a] (a, [a]) -- | MutBranch focusing on the Nothing case of a Maybe nothingMB :: (PrimMonad m, Mutable m a) => MutBranch m (Maybe a) () -- | MutBranch focusing on the Just case of a Maybe justMB :: (PrimMonad m, Mutable m a) => MutBranch m (Maybe a) a -- | MutBranch focusing on the Left case of an Either leftMB :: (PrimMonad m, Mutable m a, Mutable m b) => MutBranch m (Either a b) a -- | MutBranch focusing on the Right case of an Either rightMB :: (PrimMonad m, Mutable m a, Mutable m b) => MutBranch m (Either a b) b -- | Class of monads which can perform primitive state-transformer actions class Monad m => PrimMonad (m :: Type -> Type) -- | State token type type family PrimState (m :: Type -> Type)