packages feed

bluefin-internal 0.3.5.0 → 0.4.0.0

raw patch · 6 files changed

+156/−82 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Bluefin.Internal: handleMapHandle :: (forall (e :: Effects) (es :: Effects). e :> es => h e -> h es) -> HandleD h
- Bluefin.Internal: handleOneWayCoercion :: (forall (e :: Effects) (es :: Effects). e :> es => OneWayCoercion (h e) (h es)) -> HandleD h
- Bluefin.Internal: instance Bluefin.Internal.Handle h => Bluefin.Internal.Handle (Bluefin.Internal.HandleReader h)
+ Bluefin.Internal: [MkHandleDict] :: forall (h :: Effects -> Type). (forall (e :: Effects) (es :: Effects). e :> es => OneWayCoercible (h e) (h es)) => HandleDict h
+ Bluefin.Internal: data HandleDict (h :: Effects -> Type)
+ Bluefin.Internal: handleDictImpl :: forall (h :: Effects -> Type). Handle h => HandleDict h
+ Bluefin.Internal: handleDictOfHandleD :: forall (h :: Effects -> Type). HandleD h -> HandleDict h
+ Bluefin.Internal: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.HandleReader h e) (Bluefin.Internal.HandleReader h es)
+ Bluefin.Internal: instance Bluefin.Internal.Handle (Bluefin.Internal.HandleReader h)
+ Bluefin.Internal: withHandle :: Handle h => ((forall (e :: Effects) (es :: Effects). e :> es => OneWayCoercible (h e) (h es)) => r) -> r
+ Bluefin.Internal.CloneableHandle: instance (Bluefin.Internal.Handle h, e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.CloneableHandle.GenericCloneableHandle h e) (Bluefin.Internal.CloneableHandle.GenericCloneableHandle h es)
+ Bluefin.Internal.Examples: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Examples.Counter7 e) (Bluefin.Internal.Examples.Counter7 es)
+ Bluefin.Internal.Examples: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Examples.DynamicReader r e) (Bluefin.Internal.Examples.DynamicReader r es)
+ Bluefin.Internal.System.IO: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.System.IO.Handle e) (Bluefin.Internal.System.IO.Handle es)
- Bluefin.Internal: MkHandleD :: (forall (e :: Effects) (es :: Effects). e :> es => h e -> h es) -> HandleD (h :: Effects -> Type)
+ Bluefin.Internal: MkHandleD :: HandleDict (Any :: Effects -> Type) -> HandleD (h :: Effects -> Type)
- Bluefin.Internal: mapHandle :: forall (e :: Effects) (es :: Effects). (Handle h, e :> es) => h e -> h es
+ Bluefin.Internal: mapHandle :: forall h (e :: Effects) (es :: Effects). (Handle h, e :> es) => h e -> h es

Files

CHANGELOG.md view
@@ -1,3 +1,13 @@+# 0.4.0.0++* Move `mapHandle` out of class `Handle`++* Remove `Bluefin.Internal.handleOneWayCoercion`++* Remove `Bluefin.Internal.handleMapHandle`++* Add a variety of `Handle` functionality+ # 0.3.5.0  * Add `Bluefin.Internal.oneWayCoercibleTrustMe`
bluefin-internal.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               bluefin-internal-version:            0.3.5.0+version:            0.4.0.0 license:            MIT license-file:       LICENSE author:             Tom Ellis
src/Bluefin/Internal.hs view
@@ -16,10 +16,8 @@ import Bluefin.Internal.OneWayCoercible   ( OneWayCoercible (oneWayCoercibleImpl),     OneWayCoercibleD,-    OneWayCoercion,     gOneWayCoercible,     oneWayCoerce,-    oneWayCoerceWith,     oneWayCoercible,     unsafeOneWayCoercible,   )@@ -38,8 +36,8 @@ import Data.Kind (Type) import Data.Proxy (Proxy (Proxy)) import Data.Type.Coercion (Coercion (Coercion))-import GHC.Exts (Proxy#, proxy#)-import GHC.Generics (Generic, M1 (M1), Rec1 (Rec1), (:*:) ((:*:)))+import GHC.Exts (Any, Proxy#, proxy#)+import GHC.Generics (Generic, M1, Rec1, (:*:)) import System.IO.Unsafe (unsafePerformIO) import Unsafe.Coerce (unsafeCoerce) import Prelude hiding (drop, head, read, return)@@ -399,85 +397,136 @@ -- instance (e :> es) => 'OneWayCoercible' (Application e) (Application es) where --   oneWayCoercibleImpl = 'gOneWayCoercible' -- @+--+-- In occasional cases, @gOneWayCoercible@ won't work, in which can+-- you can instead use+--+-- @+-- instance (e :> es) => OneWayCoercible (MyHandle e) (MyHandle es) where+--   oneWayCoercibleImpl = 'oneWayCoercibleTrustMe' $ \\h -> \<mapHandle definition\>+-- @ class Handle (h :: Effects -> Type) where-  {-# MINIMAL handleImpl | mapHandle #-}--  -- | Define @handleImpl@ using 'handleMapHandle'.   handleImpl :: HandleD h-  handleImpl = MkHandleD mapHandle -  -- | Used to create compound effects, i.e. handles that contain-  -- other handles.-  ---  -- You should not define this method in your type classes. Instead-  -- define @handleImpl@.  In a future version of Bluefin, @mapHandle@-  -- will no longer be a method.  If you previously had a definition-  -- of @mapHandle@, for example like this:-  ---  -- @-  -- instance Handle MyHandle where-  --   mapHandle h = \<mapHandle definition\>-  -- @-  ---  -- you should change it to-  ---  -- @-  -- data MyHandle e = ...-  --   deriving (Generic)-  --   deriving (Handle) via 'OneWayCoercibleHandle' MyHandle-  ---  -- instance (e :> es) => 'OneWayCoercible' (MyHandle e) (MyHandle es) where-  --   'oneWayCoercibleImpl' = 'gOneWayCoercible'-  -- @-  ---  -- If that doesn't work for any reason you can always reuse your old-  -- definition of @mapHandle@ as follows.  However,-  -- 'handleMapHandle' will be removed at some point in the future, so-  -- you can [open a new issue on-  -- Bluefin](https://github.com/tomjaguarpaw/bluefin/issues/new) to-  -- ask for advice.-  ---  -- @-  -- instance Handle MyHandle where-  --   handleImpl = handleMapHandle $ \\h -> \<mapHandle definition\>-  -- @-  mapHandle :: (e :> es) => h e -> h es-  mapHandle = case handleImpl of MkHandleD f -> f+-- | This was previously a method of class 'Handle' using which you+-- could define @Handle@ instances. Now, you should define+-- @handleImpl@ instead.  If you previously had a definition of+-- @mapHandle@, for example like this:+--+-- @+-- instance Handle MyHandle where+--   mapHandle h = \<mapHandle definition\>+-- @+--+-- you should change it to+--+-- @+-- data MyHandle e = ...+--   deriving (Generic)+--   deriving (Handle) via 'OneWayCoercibleHandle' MyHandle+--+-- instance (e :> es) => 'OneWayCoercible' (MyHandle e) (MyHandle es) where+--   'oneWayCoercibleImpl' = 'gOneWayCoercible'+-- @+--+-- In occasional cases, @gOneWayCoercible@ won't work, in which can+-- you can instead use+--+-- @+-- instance (e :> es) => OneWayCoercible (MyHandle e) (MyHandle es) where+--   oneWayCoercibleImpl = 'oneWayCoercibleTrustMe' $ \\h -> \<mapHandle definition\>+-- @+mapHandle :: forall h e es. (Handle h, e :> es) => h e -> h es+mapHandle = case handleDictImpl @h of MkHandleDict -> oneWayCoerce +withHandle ::+  forall h r.+  (Handle h) =>+  ((forall e es. (e :> es) => OneWayCoercible (h e) (h es)) => r) ->+  r+withHandle r = case handleDictImpl @h of MkHandleDict -> r++type HandleDict :: (Effects -> Type) -> Type+data HandleDict h where+  MkHandleDict ::+    (forall e es. (e :> es) => OneWayCoercible (h e) (h es)) =>+    HandleDict h++type role HandleDict nominal++-- The essential properties of HandleD h are+--+-- (defining Handle' h =+--    forall e es. (e :> es) => OneWayCoercible (h e) (h es))+--+-- 1. It can be created by having Handle' h in scope+--+-- 2. Having it can put Handle' h into scope+--+-- 3. There is an instance+--+--      Coercible h1 h2 => Coercible (Handle' h1) (Handle' h2)+--+-- 1 is used by handleOneWayCoercible+--+-- 2 is used by withHandle+--+-- 3 is used by deriving via of OneWayCoercibleHandle+--+-- The only way I have worked out how to satisfy all three properties+-- is to have `HandleD h` not depend on `h`, instead have `Any` in+-- place of where we would use `h`.  That way we can get property 3+-- (which requires cooperation with GHC) and achieve properties 1 and+-- 2 by unsafeCoerce.+ -- | The type of the 'handleImpl' method of the 'Handle' class.--- Create a @HandleD@ using 'handleMapHandle'.+-- Create a @HandleD@ using deriving via of 'OneWayCoercibleHandle'. type HandleD :: (Effects -> Type) -> Type-newtype HandleD h = MkHandleD (forall e es. (e :> es) => h e -> h es)+newtype HandleD h = MkHandleD (HandleDict Any) --- | For defining the 'handleImpl' method of the 'Handle' class.-handleMapHandle ::-  (forall e es. (e :> es) => h e -> h es) ->-  -- | ͘-  HandleD h-handleMapHandle = MkHandleD+handleDictOfHandleD :: HandleD h -> HandleDict h+-- SPJ suggests this might be safe on ghc-devs+--+--https://mailman.haskell.org/archives/list/ghc-devs@haskell.org/thread/A4AJPPA3WSORHKCMFWAFX26XNQQVYT5R/+handleDictOfHandleD (MkHandleD f) = unsafeCoerce f +handleDictImpl :: (Handle h) => HandleDict h+handleDictImpl = handleDictOfHandleD handleImpl++type role HandleD representational+ handleOneWayCoercible ::   forall h.   (forall e es. (e :> es) => OneWayCoercible (h e) (h es)) =>   -- | ͘   HandleD h-handleOneWayCoercible = MkHandleD oneWayCoerce--handleOneWayCoercion ::-  (forall e es. (e :> es) => OneWayCoercion (h e) (h es)) ->-  -- | ͘-  HandleD h-handleOneWayCoercion owc = MkHandleD (oneWayCoerceWith owc)+-- SPJ suggests this might be safe on ghc-devs+--+--https://mailman.haskell.org/archives/list/ghc-devs@haskell.org/thread/A4AJPPA3WSORHKCMFWAFX26XNQQVYT5R/+handleOneWayCoercible = MkHandleD (unsafeCoerce (MkHandleDict @h))  instance (Handle h) => Handle (Rec1 h) where-  handleImpl = handleMapHandle $ \(Rec1 h) -> Rec1 (mapHandle h)+  handleImpl = withHandle @h handleOneWayCoercible  instance (Handle h) => Handle (M1 i t h) where-  handleImpl = handleMapHandle $ \(M1 h) -> M1 (mapHandle h)+  handleImpl = withHandle @h handleOneWayCoercible  instance (Handle h1, Handle h2) => Handle (h1 :*: h2) where-  handleImpl = handleMapHandle $ \(h1 :*: h2) -> mapHandle h1 :*: mapHandle h2+  handleImpl = withHandle @h1 (withHandle @h2 handleOneWayCoercible) +-- | It is not always possible to derive an instance of+-- 'OneWayCoercible'.  In such cases write a definition of+-- 'oneWayCoercibleImpl' using @oneWayCoercibleTrustMe@.  Its argument+-- must be a total function mapping the effect parameter of @h@.+-- Normally you'll write the function by mapping the constitients of+-- @h@ using the functions in this module like 'mapHandle', 'useImpl'+-- and 'useImplUnder'.+--+-- If this function is not total then it's possible you are violating+-- the type system, which could lead to segfaults or worse.  It's not+-- easy to supply a partial function by accident, but be careful!+-- (N.B. it must not be literally @mapHandle@ otherwise you'll have a+-- circular definition!) oneWayCoercibleTrustMe ::   (e :> es) =>   (forall e' es'. (e' :> es') => h e' -> h es') ->@@ -1582,6 +1631,7 @@     (\() -> k)  newtype HandleReader h e = UnsafeMkHandleReader (State (h e) e)+  deriving (Handle) via OneWayCoercibleHandle (HandleReader h)  -- In general this is really tremendously unsafe because we could take -- an `HandleReader h e`, map it to `HandleReader h es`, write an `h@@ -1644,11 +1694,8 @@      useImplIn k h' -instance (Handle h) => Handle (HandleReader h) where-  -- This handleImpl is now a special case that doesn't use-  -- OneWayCoercion. We can only fix that when we store a-  -- OneWayCoercion inside `Handle`.-  handleImpl = handleMapHandle mapHandleReader+instance (e :> es) => OneWayCoercible (HandleReader h e) (HandleReader h es) where+  oneWayCoercibleImpl = unsafeOneWayCoercible  newtype ConstEffect r (e :: Effects) = MkConstEffect r   deriving (Handle) via OneWayCoercibleHandle (ConstEffect r)
src/Bluefin/Internal/CloneableHandle.hs view
@@ -216,9 +216,13 @@ -- a 'CloneableHandle' instance for your type, as long as it is a -- product type of @CloneableHandle@s. newtype GenericCloneableHandle h e = MkGenericCloneableHandle (h e)+  deriving newtype (Handle) -instance (Handle h) => Handle (GenericCloneableHandle h) where-  handleImpl = handleMapHandle $ \(MkGenericCloneableHandle h) ->+instance+  (Handle h, e :> es) =>+  OneWayCoercible (GenericCloneableHandle h e) (GenericCloneableHandle h es)+  where+  oneWayCoercibleImpl = oneWayCoercibleTrustMe $ \(MkGenericCloneableHandle h) ->     MkGenericCloneableHandle (mapHandle h)  instance
src/Bluefin/Internal/Examples.hs view
@@ -6,9 +6,6 @@  import Bluefin.Internal hiding (b, w) import Bluefin.Internal.OneWayCoercible-  ( OneWayCoercible (oneWayCoercibleImpl),-    gOneWayCoercible,-  ) import Bluefin.Internal.Pipes   ( Producer,     runEffect,@@ -25,7 +22,6 @@ import Data.Foldable (for_) import Data.Monoid (Any (Any, getAny)) import Data.Proxy (Proxy (Proxy))-import GHC.Generics (Generic) import Text.Read (readMaybe) import Prelude hiding   ( break,@@ -791,9 +787,13 @@     counter7State :: State Int e,     counter7Stream :: Stream String e   }+  deriving (Handle) via OneWayCoercibleHandle Counter7 -instance Handle Counter7 where-  handleImpl = handleMapHandle $ \c ->+-- | The "forall" in the type of @incCounter7@ means that we can't+-- derive the @OneWayCoercible@ instance with 'gOneWayCoercible' so+-- instead we use @oneWayCoercibleTrustMe@.+instance (e :> es) => OneWayCoercible (Counter7 e) (Counter7 es) where+  oneWayCoercibleImpl = oneWayCoercibleTrustMe $ \c ->     MkCounter7       { incCounter7Impl = \ex -> useImplUnder (incCounter7Impl c ex),         counter7State = mapHandle (counter7State c),@@ -1036,13 +1036,20 @@     Left e -> "Caught IOException:\n" ++ show e     Right contents -> contents +-- | The "forall" in the type of @localRImpl@ means that we can't+-- derive the @OneWayCoercible@ instance with 'gOneWayCoercible' so+-- instead we use @oneWayCoercibleTrustMe@. data DynamicReader r e = DynamicReader   { askLRImpl :: Eff e r,     localLRImpl :: forall e' a. (r -> r) -> Eff e' a -> Eff (e' :& e) a   }+  deriving (Handle) via OneWayCoercibleHandle (DynamicReader r) -instance Handle (DynamicReader r) where-  handleImpl = handleMapHandle $ \h ->+instance+  (e :> es) =>+  OneWayCoercible (DynamicReader r e) (DynamicReader r es)+  where+  oneWayCoercibleImpl = oneWayCoercibleTrustMe $ \h ->     DynamicReader       { askLRImpl = useImpl (askLRImpl h),         localLRImpl = \f k -> useImplUnder (localLRImpl h f k)
src/Bluefin/Internal/System/IO.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DerivingVia #-}+ module Bluefin.Internal.System.IO   ( module Bluefin.Internal.System.IO,     System.IO.IOMode (..),@@ -9,21 +11,25 @@     IOE,     bracket,     effIO,-    handleMapHandle,     mapHandle,+    oneWayCoercibleTrustMe,     useImplIn,     (:&),     (:>),   ) import Bluefin.Internal qualified+import Bluefin.Internal.OneWayCoercible (OneWayCoercible (oneWayCoercibleImpl)) import System.IO qualified  -- We can probably get away without the IOE and just use -- unsafeProvideIO on all Handle functions data Handle e = UnsafeMkHandle System.IO.Handle (IOE e)+  deriving+    (Bluefin.Internal.Handle)+    via Bluefin.Internal.OneWayCoercibleHandle Handle -instance Bluefin.Internal.Handle Handle where-  handleImpl = handleMapHandle $ \(UnsafeMkHandle h io) ->+instance (e :> es) => OneWayCoercible (Handle e) (Handle es) where+  oneWayCoercibleImpl = oneWayCoercibleTrustMe $ \(UnsafeMkHandle h io) ->     UnsafeMkHandle h (mapHandle io)  withFile ::