bluefin-internal 0.3.1.0 → 0.3.2.0
raw patch · 4 files changed
+305/−2 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Bluefin.Internal: instance (Bluefin.Internal.Handle h1, Bluefin.Internal.Handle h2) => Bluefin.Internal.Handle (h1 GHC.Generics.:*: h2)
+ Bluefin.Internal: instance Bluefin.Internal.Handle h => Bluefin.Internal.Handle (GHC.Generics.M1 i t h)
+ Bluefin.Internal: instance Bluefin.Internal.Handle h => Bluefin.Internal.Handle (GHC.Generics.Rec1 h)
+ Bluefin.Internal.CloneableHandle: MkArrow :: (forall (e :: Effects). () => h1 e -> h2 (e :& es)) -> (:~>) (h1 :: Effects -> Type) (h2 :: Effects -> Type) (es :: Effects)
+ Bluefin.Internal.CloneableHandle: MkCloneableHandleD :: (forall (e :: Effects). () => HandleCloner h h e) -> CloneableHandleD (h :: Effects -> Type)
+ Bluefin.Internal.CloneableHandle: MkGenericCloneableHandle :: h e -> GenericCloneableHandle (h :: k -> Type) (e :: k)
+ Bluefin.Internal.CloneableHandle: MkHandleCloner :: (forall r. () => h1 es -> (forall (e :: Effects). () => h2 e -> Eff (e :& es) r) -> Eff es r) -> HandleCloner (h1 :: Effects -> Type) (h2 :: Effects -> Type) (es :: Effects)
+ Bluefin.Internal.CloneableHandle: abstract :: forall h2 h1 (es :: Effects). Handle h2 => (forall (e :: Effects). () => h1 e -> h2 (e :& es)) -> (h1 :~> h2) es
+ Bluefin.Internal.CloneableHandle: apHC :: forall (h :: Effects -> Type) (h1 :: Effects -> Type) (h2 :: Effects -> Type) (e :: Effects). (Handle h, Handle h1, Handle h2) => HandleCloner h (h1 :~> h2) e -> HandleCloner h h1 e -> HandleCloner h h2 e
+ Bluefin.Internal.CloneableHandle: app :: forall h2 h1 (e :: Effects). Handle h2 => (h1 :~> h2) e -> h1 e -> h2 e
+ Bluefin.Internal.CloneableHandle: class Handle h => CloneableHandle (h :: Effects -> Type)
+ Bluefin.Internal.CloneableHandle: class Handle h => GCloneableHandle (h :: Effects -> Type)
+ Bluefin.Internal.CloneableHandle: class Generic1 (f :: k -> Type)
+ Bluefin.Internal.CloneableHandle: class Monad m => MonadIO (m :: Type -> Type)
+ Bluefin.Internal.CloneableHandle: class MonadIO m => MonadUnliftIO (m :: Type -> Type)
+ Bluefin.Internal.CloneableHandle: cloneHandle2 :: forall h1 h2 (e1 :: Effects) (es :: Effects) r. (Handle h1, Handle h2, e1 :> es) => HandleCloner h1 h2 es -> h1 e1 -> (forall (e :: Effects). () => h2 e -> Eff (e :& es) r) -> Eff es r
+ Bluefin.Internal.CloneableHandle: cloneHandleClass :: forall (e1 :: Effects) (es :: Effects) h r. (e1 :> es, CloneableHandle h) => h e1 -> (forall (e :: Effects). () => h e -> Eff (e :& es) r) -> Eff es r
+ Bluefin.Internal.CloneableHandle: cloneableHandleImpl :: CloneableHandle h => CloneableHandleD h
+ Bluefin.Internal.CloneableHandle: fmapHC :: forall (h :: Effects -> Type) (h1 :: Effects -> Type) (h2 :: Effects -> Type) (e :: Effects). (Handle h, Handle h1, Handle h2) => (h1 :~> h2) e -> HandleCloner h h1 e -> HandleCloner h h2 e
+ Bluefin.Internal.CloneableHandle: gCloneableHandle :: forall (h :: Effects -> Type). (Handle h, Generic1 h, GCloneableHandle (Rep1 h)) => CloneableHandleD h
+ Bluefin.Internal.CloneableHandle: gCloneableHandleImpl :: GCloneableHandle h => CloneableHandleD h
+ Bluefin.Internal.CloneableHandle: getHandleCloner :: forall (h :: Effects -> Type) (e :: Effects). GCloneableHandle h => HandleCloner h h e
+ Bluefin.Internal.CloneableHandle: hcException :: forall ex (e :: Effects). HandleCloner (Exception ex) (Exception ex) e
+ Bluefin.Internal.CloneableHandle: hcHandleReader :: forall (h :: Effects -> Type) (e :: Effects). CloneableHandle h => HandleCloner (HandleReader h) (HandleReader h) e
+ Bluefin.Internal.CloneableHandle: hcIOE :: forall (e :: Effects). HandleCloner IOE IOE e
+ Bluefin.Internal.CloneableHandle: hcReader :: forall r (e :: Effects). HandleCloner (Reader r) (Reader r) e
+ Bluefin.Internal.CloneableHandle: hcState :: forall s (e :: Effects). HandleCloner (State s) (State s) e
+ Bluefin.Internal.CloneableHandle: infixl 9 `apHC`
+ Bluefin.Internal.CloneableHandle: infixr 9 :~>
+ Bluefin.Internal.CloneableHandle: instance (Bluefin.Internal.CloneableHandle.GCloneableHandle h1, Bluefin.Internal.CloneableHandle.GCloneableHandle h2) => Bluefin.Internal.CloneableHandle.GCloneableHandle (h1 GHC.Generics.:*: h2)
+ Bluefin.Internal.CloneableHandle: instance (Bluefin.Internal.Handle h, GHC.Generics.Generic1 h, Bluefin.Internal.CloneableHandle.GCloneableHandle (GHC.Generics.Rep1 h)) => Bluefin.Internal.CloneableHandle.CloneableHandle (Bluefin.Internal.CloneableHandle.GenericCloneableHandle h)
+ Bluefin.Internal.CloneableHandle: instance (Bluefin.Internal.Handle h1, Bluefin.Internal.Handle h2) => Bluefin.Internal.Handle (Bluefin.Internal.CloneableHandle.HandleCloner h1 h2)
+ Bluefin.Internal.CloneableHandle: instance (Bluefin.Internal.Handle h1, Bluefin.Internal.Handle h2) => Bluefin.Internal.Handle (h1 Bluefin.Internal.CloneableHandle.:~> h2)
+ Bluefin.Internal.CloneableHandle: instance (Bluefin.Internal.Handle h1, Bluefin.Internal.Handle h2) => Bluefin.Internal.OneWayCoercible.OneWayCoercible ((Bluefin.Internal.CloneableHandle.:~>) h1 h2 e) ((Bluefin.Internal.CloneableHandle.:~>) h1 h2 es)
+ Bluefin.Internal.CloneableHandle: instance (Bluefin.Internal.Handle h1, Bluefin.Internal.Handle h2) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.CloneableHandle.HandleCloner h1 h2 e) (Bluefin.Internal.CloneableHandle.HandleCloner h1 h2 es)
+ Bluefin.Internal.CloneableHandle: instance (TypeError ...) => Bluefin.Internal.CloneableHandle.CloneableHandle (Bluefin.Internal.Coroutine a b)
+ Bluefin.Internal.CloneableHandle: instance (TypeError ...) => Bluefin.Internal.CloneableHandle.CloneableHandle (Bluefin.Internal.Writer w)
+ Bluefin.Internal.CloneableHandle: instance Bluefin.Internal.CloneableHandle.CloneableHandle (Bluefin.Internal.Exception a)
+ Bluefin.Internal.CloneableHandle: instance Bluefin.Internal.CloneableHandle.CloneableHandle (Bluefin.Internal.Reader r)
+ Bluefin.Internal.CloneableHandle: instance Bluefin.Internal.CloneableHandle.CloneableHandle (Bluefin.Internal.State s)
+ Bluefin.Internal.CloneableHandle: instance Bluefin.Internal.CloneableHandle.CloneableHandle Bluefin.Internal.IOE
+ Bluefin.Internal.CloneableHandle: instance Bluefin.Internal.CloneableHandle.CloneableHandle h => Bluefin.Internal.CloneableHandle.CloneableHandle (Bluefin.Internal.HandleReader h)
+ Bluefin.Internal.CloneableHandle: instance Bluefin.Internal.CloneableHandle.CloneableHandle h => Bluefin.Internal.CloneableHandle.GCloneableHandle (GHC.Generics.Rec1 h)
+ Bluefin.Internal.CloneableHandle: instance Bluefin.Internal.CloneableHandle.GCloneableHandle h => Bluefin.Internal.CloneableHandle.GCloneableHandle (GHC.Generics.M1 i t h)
+ Bluefin.Internal.CloneableHandle: instance Bluefin.Internal.Handle h => Bluefin.Internal.Handle (Bluefin.Internal.CloneableHandle.GenericCloneableHandle h)
+ Bluefin.Internal.CloneableHandle: liftHC2 :: forall (h :: Effects -> Type) h1 h2 hr (es :: Effects). (Handle h, Handle h1, Handle h2) => (forall (e :: Effects). () => h1 e -> h2 e -> hr e) -> HandleCloner h h1 es -> HandleCloner h h2 es -> HandleCloner h hr es
+ Bluefin.Internal.CloneableHandle: liftIO :: MonadIO m => IO a -> m a
+ Bluefin.Internal.CloneableHandle: lmapHC :: forall (h :: Effects -> Type) (h2 :: Effects -> Type) (h1 :: Effects -> Type) (e :: Effects). (Handle h, Handle h2) => (h1 :~> h2) e -> HandleCloner h2 h e -> HandleCloner h1 h e
+ Bluefin.Internal.CloneableHandle: newtype ( (h1 :: Effects -> Type) :~> (h2 :: Effects -> Type) ) (es :: Effects)
+ Bluefin.Internal.CloneableHandle: newtype CloneableHandleD (h :: Effects -> Type)
+ Bluefin.Internal.CloneableHandle: newtype GenericCloneableHandle (h :: k -> Type) (e :: k)
+ Bluefin.Internal.CloneableHandle: newtype HandleCloner (h1 :: Effects -> Type) (h2 :: Effects -> Type) (es :: Effects)
+ Bluefin.Internal.CloneableHandle: pureHC :: forall h2 (e :: Effects) (h1 :: Effects -> Type). h2 e -> HandleCloner h1 h2 e
+ Bluefin.Internal.CloneableHandle: withEffToIOCloneHandle :: forall (e1 :: Effects) (es :: Effects) h a. (e1 :> es, CloneableHandle h) => IOE e1 -> h es -> ((forall r. () => (forall (e :: Effects). () => IOE e -> h e -> Eff e r) -> IO r) -> IO a) -> Eff es a
+ Bluefin.Internal.CloneableHandle: withRunInIO :: MonadUnliftIO m => ((forall a. () => m a -> IO a) -> IO b) -> m b
Files
- CHANGELOG.md +4/−0
- bluefin-internal.cabal +2/−1
- src/Bluefin/Internal.hs +10/−1
- src/Bluefin/Internal/CloneableHandle.hs +289/−0
CHANGELOG.md view
@@ -1,3 +1,7 @@+# 0.3.2.0++* Add `Bluefin.Internal.CloneHandle`+ # 0.3.1.0 * Add `Bluefin.Internal.DslBuilder`
bluefin-internal.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: bluefin-internal-version: 0.3.1.0+version: 0.3.2.0 license: MIT license-file: LICENSE author: Tom Ellis@@ -83,6 +83,7 @@ monad-control < 1.1 exposed-modules: Bluefin.Internal,+ Bluefin.Internal.CloneableHandle, Bluefin.Internal.DslBuilder, Bluefin.Internal.DslBuilderEffects, Bluefin.Internal.Examples,
src/Bluefin/Internal.hs view
@@ -38,7 +38,7 @@ import Data.Proxy (Proxy (Proxy)) import Data.Type.Coercion (Coercion (Coercion)) import GHC.Exts (Proxy#, proxy#)-import GHC.Generics (Generic)+import GHC.Generics (Generic, M1 (M1), Rec1 (Rec1), (:*:) ((:*:))) import System.IO.Unsafe (unsafePerformIO) import Unsafe.Coerce (unsafeCoerce) import Prelude hiding (drop, head, read, return)@@ -464,6 +464,15 @@ -- | ͘ HandleD h handleOneWayCoercion owc = MkHandleD (oneWayCoerceWith owc)++instance (Handle h) => Handle (Rec1 h) where+ handleImpl = handleMapHandle $ \(Rec1 h) -> Rec1 (mapHandle h)++instance (Handle h) => Handle (M1 i t h) where+ handleImpl = handleMapHandle $ \(M1 h) -> M1 (mapHandle h)++instance (Handle h1, Handle h2) => Handle (h1 :*: h2) where+ handleImpl = handleMapHandle $ \(h1 :*: h2) -> mapHandle h1 :*: mapHandle h2 -- { OneWayCoercibleHandle
+ src/Bluefin/Internal/CloneableHandle.hs view
@@ -0,0 +1,289 @@+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE QuantifiedConstraints #-}+{-# LANGUAGE UndecidableInstances #-}++module Bluefin.Internal.CloneableHandle+ ( module Bluefin.Internal.CloneableHandle,+ MonadUnliftIO (withRunInIO),+ MonadIO (liftIO),+ Generic1,+ )+where++import Bluefin.Internal hiding (b, race, w)+import Bluefin.Internal.OneWayCoercible+ ( OneWayCoercible (..),+ unsafeOneWayCoercible,+ )+import Control.Monad.IO.Unlift (MonadIO (liftIO), MonadUnliftIO (withRunInIO))+import Data.Coerce (coerce)+import GHC.Generics+ ( Generic1 (..),+ M1 (M1),+ Rec1 (Rec1),+ (:*:) ((:*:)),+ )+import GHC.TypeLits (ErrorMessage (Text), TypeError)++withEffToIOCloneHandle ::+ (e1 :> es, CloneableHandle h) =>+ IOE e1 ->+ -- | Handle accessible in the continuation+ h es ->+ -- | Continuation with the unlifting function in scope.+ ((forall r. (forall e. IOE e -> h e -> Eff e r) -> IO r) -> IO a) ->+ Eff es a+withEffToIOCloneHandle io h k = do+ withEffToIO_ io $ \runInIO -> do+ k $ \body -> do+ runInIO $ do+ cloneHandleClass h $ \h' -> do+ cloneHandleClass io $ \io' -> do+ body (mapHandle io') (mapHandle h')++newtype HandleCloner h1 h2 es+ = MkHandleCloner+ ( forall r.+ h1 es ->+ (forall e. h2 e -> Eff (e :& es) r) ->+ Eff es r+ )++instance (Handle h1, Handle h2) => Handle (HandleCloner h1 h2) where+ handleImpl = handleOneWayCoercible++instance+ (Handle h1, Handle h2) =>+ OneWayCoercible+ (HandleCloner h1 h2 e)+ (HandleCloner h1 h2 es)+ where+ -- FIXME: These instances for higher rank types are annoying+ oneWayCoercibleImpl = unsafeOneWayCoercible++cloneHandle2 ::+ (Handle h1, Handle h2, e1 :> es) =>+ HandleCloner h1 h2 es ->+ h1 e1 ->+ (forall e. h2 e -> Eff (e :& es) r) ->+ Eff es r+cloneHandle2 (MkHandleCloner c) h1 = c (mapHandle h1)++instance CloneableHandle IOE where+ cloneableHandleImpl = MkCloneableHandleD hcIOE++hcIOE :: HandleCloner IOE IOE e+hcIOE = MkHandleCloner $ \io k -> do+ useImplIn k (mapHandle io)++-- | Cloning a @State@ copies its contents to a new @State@. Changes+-- to one will not effect the other.+instance CloneableHandle (State s) where+ cloneableHandleImpl = MkCloneableHandleD hcState++hcState :: HandleCloner (State s) (State s) e+hcState = MkHandleCloner $ \st k -> do+ s <- get st+ evalState s $ \st' ->+ useImplIn k (mapHandle st')++instance CloneableHandle (Exception a) where+ cloneableHandleImpl = MkCloneableHandleD hcException++hcException :: HandleCloner (Exception ex) (Exception ex) e+hcException = MkHandleCloner $ \ex k -> do+ useImplIn k (mapHandle ex)++instance CloneableHandle (Reader r) where+ cloneableHandleImpl = MkCloneableHandleD hcReader++hcReader :: HandleCloner (Reader r) (Reader r) e+hcReader = MkHandleCloner $ \(MkReader s) k -> do+ cloneHandleClass s $ \s' -> do+ useImplIn k (MkReader (mapHandle s'))++-- | Cloning a @HandleReader@ copies its contents to a new+-- @HandleReader@. Changes to one will not effect the other.+instance (CloneableHandle h) => CloneableHandle (HandleReader h) where+ cloneableHandleImpl = MkCloneableHandleD hcHandleReader++cloneHandleClass ::+ (e1 :> es, CloneableHandle h) =>+ h e1 ->+ (forall e. h e -> Eff (e :& es) r) ->+ Eff es r+cloneHandleClass =+ cloneHandle2 (case cloneableHandleImpl of MkCloneableHandleD c' -> c')++hcHandleReader :: (CloneableHandle h) => HandleCloner (HandleReader h) (HandleReader h) e+hcHandleReader = MkHandleCloner $ \hr k -> do+ h <- askHandle hr+ cloneHandleClass h $ \h' -> do+ runHandleReader h' $ \hr' -> do+ useImplIn k (mapHandle hr')++instance+ (TypeError (Text "Coroutine cannot be cloned. Perhaps you want an STM channel?")) =>+ CloneableHandle (Coroutine a b)+ where+ cloneableHandleImpl =+ error "instance CloneableHandle (Coroutine a b) not implemented"++instance+ (TypeError (Text "Writer cannot be cloned. Perhaps you want an STM channel?")) =>+ CloneableHandle (Writer w)+ where+ cloneableHandleImpl =+ error "instance CloneableHandle (Writer a) not implemented"++newtype (h1 :~> h2) es = MkArrow (forall e. h1 e -> h2 (e :& es))++instance (Handle h1, Handle h2) => Handle (h1 :~> h2) where+ handleImpl = handleOneWayCoercible++instance+ (Handle h1, Handle h2) =>+ OneWayCoercible+ ((h1 :~> h2) e)+ ((h1 :~> h2) es)+ where+ -- FIXME: These instances for higher rank types are annoying+ oneWayCoercibleImpl = unsafeOneWayCoercible++abstract :: (Handle h2) => (forall e. h1 e -> h2 (e :& es)) -> (h1 :~> h2) es+abstract k = MkArrow (mapHandle . k)++app ::+ (Handle h2) =>+ (h1 :~> h2) e ->+ h1 e ->+ h2 e+app (MkArrow f) h1 = makeOpHandle (f h1)+ where+ makeOpHandle :: forall h e. (Handle h) => h (e :& e) -> h e+ makeOpHandle = case have @(e :& e) @e (subsume1 (eq ZW)) of+ Dict -> mapHandle++lmapHC ::+ (Handle h, Handle h2) =>+ (h1 :~> h2) e ->+ HandleCloner h2 h e ->+ HandleCloner h1 h e+lmapHC f hc = MkHandleCloner $ \h1 k1 -> cloneHandle2 hc (app f h1) k1++pureHC :: h2 e -> HandleCloner h1 h2 e+pureHC h2 = MkHandleCloner $ \_ k -> makeOp (k h2)++fmapHC ::+ (Handle h, Handle h1, Handle h2) =>+ (h1 :~> h2) e ->+ HandleCloner h h1 e ->+ HandleCloner h h2 e+fmapHC f h = pureHC f `apHC` h++apHC ::+ (Handle h, Handle h1, Handle h2) =>+ HandleCloner h (h1 :~> h2) e ->+ HandleCloner h h1 e ->+ HandleCloner h h2 e+apHC cf c1 = MkHandleCloner $ \h k2 -> do+ cloneHandle2 (mapHandle cf) h $ \hf -> do+ cloneHandle2 (mapHandle c1) h $ \h1 -> do+ useImplIn k2 (app (mapHandle hf) (mapHandle h1))++liftHC2 ::+ forall h h1 h2 hr es.+ (Handle h, Handle h1, Handle h2) =>+ (forall e. h1 e -> h2 e -> hr e) ->+ HandleCloner h h1 es ->+ HandleCloner h h2 es ->+ HandleCloner h hr es+liftHC2 f c1 c2 = MkHandleCloner $ \h kr -> do+ cloneHandle2 c1 h $ \h1 -> do+ cloneHandle2 (mapHandle c2) h $ \h2 -> do+ useImplIn kr (f (mapHandle h1) (mapHandle h2))++infixr 9 :~>++infixl 9 `apHC`++-- | You can use @DerivingVia@ with @GenericCloneableHandle@ to derive+-- a 'CloneableHandle' instance for your type, as long as it is a+-- product type of @CloneableHandle@s.+newtype GenericCloneableHandle h e = MkGenericCloneableHandle (h e)++instance (Handle h) => Handle (GenericCloneableHandle h) where+ handleImpl = handleMapHandle $ \(MkGenericCloneableHandle h) ->+ MkGenericCloneableHandle (mapHandle h)++instance+ (Handle h, Generic1 h, GCloneableHandle (Rep1 h)) =>+ CloneableHandle (GenericCloneableHandle h)+ where+ cloneableHandleImpl = coerce (gCloneableHandle @h)++newtype CloneableHandleD h = MkCloneableHandleD (forall e. HandleCloner h h e)++getHandleCloner :: (GCloneableHandle h) => HandleCloner h h e+getHandleCloner = case gCloneableHandleImpl of MkCloneableHandleD c -> c++gCloneableHandle ::+ forall h.+ (Handle h, Generic1 h) =>+ (GCloneableHandle (Rep1 h)) =>+ CloneableHandleD h+gCloneableHandle =+ MkCloneableHandleD+ ( fmapHC+ (abstract (mapHandle . to1))+ (lmapHC (abstract (mapHandle . from1)) getHandleCloner)+ )++-- | You can define a @CloneableHandle@ instance for your @Handle@ as+-- long as it is a product type of @CloneableHandle@s. To define the+-- instance, use @DerivingVia@ and 'GenericCloneableHandle'. For+-- example:+--+-- @+-- data MyHandle e = MkMyHandle ('Bluefin.Exception.Exception' String e) ('Bluefin.State.State' Int e)+-- deriving ('Bluefin.Compound.Generic', 'Generic1')+-- deriving ('Bluefin.Compound.Handle') via t'Bluefin.Compound.OneWayCoercibleHandle' MyHandle+-- deriving ('CloneableHandle') via 'GenericCloneableHandle' MyHandle+--+-- instance (e t'Bluefin.Eff.:>' es) => t'Bluefin.Compound.OneWayCoercible' (MyHandle e) (MyHandle es) where+-- 'Bluefin.Compound.oneWayCoercibleImpl' = 'Bluefin.Compound.gOneWayCoercible'+-- @+class (Handle h) => CloneableHandle h where+ -- | Blah+ cloneableHandleImpl :: CloneableHandleD h++-- | @Generic@ implementation detail of+-- 'GenericCloneableHandle'. Bluefin users should never need to use+-- this directly.+class (Handle h) => GCloneableHandle h where+ gCloneableHandleImpl :: CloneableHandleD h++-- | A cloneable handle is generically cloneable+instance+ (CloneableHandle h) =>+ GCloneableHandle (Rec1 h)+ where+ gCloneableHandleImpl = coerce (cloneableHandleImpl @h)++-- | An annotated cloneable handle is generically cloneable+instance+ (GCloneableHandle h) =>+ GCloneableHandle (M1 i t h)+ where+ gCloneableHandleImpl = coerce (gCloneableHandleImpl @h)++-- | A pair of cloneable handles is generically cloneable+instance+ (GCloneableHandle h1, GCloneableHandle h2) =>+ GCloneableHandle (h1 :*: h2)+ where+ gCloneableHandleImpl =+ MkCloneableHandleD $+ (abstract $ \h1 -> abstract $ \h2 -> mapHandle h1 :*: mapHandle h2)+ `fmapHC` lmapHC (abstract $ \(h1 :*: _) -> mapHandle h1) getHandleCloner+ `apHC` lmapHC (abstract $ \(_ :*: h2) -> mapHandle h2) getHandleCloner