Safe Haskell | None |
---|---|
Language | GHC2021 |
Simple reference counting with linear types inspired by Advanced Topics in Types and Programming Languages Chapter 1
Synopsis
- data Alias (m :: Type -> Type) a
- class Shareable (m :: Type -> Type) a where
- share :: a %1 -> m (a, a)
- class Forgettable (m :: Type -> Type) a where
- forget :: a %1 -> m ()
- get :: MonadIO μ => Alias μ a %1 -> μ (a, a %1 -> μ ())
- use :: forall (μ :: Type -> Type) a b. Alias μ a %1 -> (a %1 -> (a, b)) %1 -> (Alias μ a, b)
- useM :: forall m (μ :: Type -> Type) a b. MonadIO m => Alias μ a %1 -> (a %1 -> m (a, b)) %1 -> m (Alias μ a, b)
- modify :: forall a (μ :: Type -> Type). (a %1 -> a) %1 -> Alias μ a %1 -> Alias μ a
- modifyM :: forall m a (μ :: Type -> Type). MonadIO m => (a %1 -> m a) %1 -> Alias μ a %1 -> m (Alias μ a)
- hoist :: MonadIO m => ((a %1 -> m ()) %1 -> b %1 -> μ ()) %1 -> (a %1 -> b) %1 -> Alias m a %1 -> Alias μ b
- newAlias :: MonadIO m => (a %1 -> μ ()) %1 -> a %1 -> m (Alias μ a)
The heart of aliasing
class Shareable (m :: Type -> Type) a where Source #
Nothing
share :: a %1 -> m (a, a) Source #
Share a linear resource
Careful! You must make sure that all aliases recursively nested within
this structure a
are properly shared/incremented.
If you fail to implement this correctly, reference counting won't be sound.
Good thing is we can do this automatically! It's much less bug-prone,
especially if you update the definition of a datatype. Your a
just needs
to instance Generic
.
Instances
class Forgettable (m :: Type -> Type) a where Source #
Instances
Forgettable m Int Source # | |
Defined in Data.Linear.Alias | |
Forgettable m a => Forgettable m (IntMap a) Source # | |
Defined in Data.Linear.Alias | |
Forgettable m a => Forgettable m [a] Source # | |
Defined in Data.Linear.Alias | |
(Forgettable m a, Forgettable m b) => Forgettable m (a, b) Source # | |
Defined in Data.Linear.Alias | |
Forgettable μ (Alias μ a) Source # | |
Defined in Data.Linear.Alias | |
(Forgettable m a, Forgettable m b, Forgettable m c) => Forgettable m (a, b, c) Source # | |
Defined in Data.Linear.Alias |
get :: MonadIO μ => Alias μ a %1 -> μ (a, a %1 -> μ ()) Source #
This function returns a value that is aliased in a linear pair with a function to free the linear value. Since both the value and freeing function must be consumed linearly, it is guaranteed that the returned function is the one used to free the resource.
The cleanup function can be one of two things:
- If the returned value was the last reference, the function is the one
passed as an argument to
new
- Otherwise, if this isn't the last reference to the value, the freeing function will be a no-op, but still must be called on the value.
Usage:
(x, cleanup) <- Alias.get ref x' <- useSomehow x cleanup x'
Using and modifying aliased resources
use :: forall (μ :: Type -> Type) a b. Alias μ a %1 -> (a %1 -> (a, b)) %1 -> (Alias μ a, b) Source #
Like useM
useM :: forall m (μ :: Type -> Type) a b. MonadIO m => Alias μ a %1 -> (a %1 -> m (a, b)) %1 -> m (Alias μ a, b) Source #
Use a reference value in an action that uses that value linearly without destroying it.
The value with the same reference count will be returned together with a byproduct of the linear computation.
modify :: forall a (μ :: Type -> Type). (a %1 -> a) %1 -> Alias μ a %1 -> Alias μ a Source #
Like modifyM
modifyM :: forall m a (μ :: Type -> Type). MonadIO m => (a %1 -> m a) %1 -> Alias μ a %1 -> m (Alias μ a) Source #
Run a monadic function that modifies a reference counted resource.
hoist :: MonadIO m => ((a %1 -> m ()) %1 -> b %1 -> μ ()) %1 -> (a %1 -> b) %1 -> Alias m a %1 -> Alias μ b Source #