bluefin-internal 0.2.1.0 → 0.3.0.0
raw patch · 5 files changed
+267/−85 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Bluefin.Internal: instance Bluefin.Internal.Handle (Bluefin.Internal.Exception s)
+ Bluefin.Internal: MkOneWayCoercibleHandle :: a es -> OneWayCoercibleHandle (a :: k -> Type) (es :: k)
+ Bluefin.Internal: handleOneWayCoercible :: forall (h :: Effects -> Type). (forall (e :: Effects) (es :: Effects). e :> es => OneWayCoercible (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 (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.ConstEffect r e) (Bluefin.Internal.ConstEffect r es)
+ Bluefin.Internal: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Coroutine a b e) (Bluefin.Internal.Coroutine a b es)
+ Bluefin.Internal: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Eff e r) (Bluefin.Internal.Eff es r)
+ Bluefin.Internal: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Eff e) (Bluefin.Internal.Eff es)
+ Bluefin.Internal: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Exception ex e) (Bluefin.Internal.Exception ex es)
+ Bluefin.Internal: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.IOE e) (Bluefin.Internal.IOE es)
+ Bluefin.Internal: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Reader r e) (Bluefin.Internal.Reader r es)
+ Bluefin.Internal: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.State s e) (Bluefin.Internal.State s es)
+ Bluefin.Internal: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Writer w e) (Bluefin.Internal.Writer w es)
+ Bluefin.Internal: instance (forall (e' :: Bluefin.Internal.Effects) (es' :: Bluefin.Internal.Effects). (e' Bluefin.Internal.:> es') => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.OneWayCoercibleHandle h e') (Bluefin.Internal.OneWayCoercibleHandle h es')) => Bluefin.Internal.Handle (Bluefin.Internal.OneWayCoercibleHandle h)
+ Bluefin.Internal: instance Bluefin.Internal.Handle (Bluefin.Internal.Exception exn)
+ Bluefin.Internal: instance forall k (a :: k -> *) (es :: k). GHC.Generics.Generic (Bluefin.Internal.OneWayCoercibleHandle a es)
+ Bluefin.Internal: instance forall k (h :: k -> *) (e :: k) (es :: k). Bluefin.Internal.OneWayCoercible.OneWayCoercible (h e) (h es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.OneWayCoercibleHandle h e) (Bluefin.Internal.OneWayCoercibleHandle h es)
+ Bluefin.Internal: newtype OneWayCoercibleHandle (a :: k -> Type) (es :: k)
+ Bluefin.Internal.Examples: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Examples.Application e) (Bluefin.Internal.Examples.Application es)
+ Bluefin.Internal.Examples: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Examples.Counter5 e) (Bluefin.Internal.Examples.Counter5 es)
+ Bluefin.Internal.Examples: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Examples.Counter6 e) (Bluefin.Internal.Examples.Counter6 es)
+ Bluefin.Internal.Examples: instance (e Bluefin.Internal.:> es) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Bluefin.Internal.Examples.FileSystem e) (Bluefin.Internal.Examples.FileSystem es)
+ Bluefin.Internal.Examples: instance GHC.Generics.Generic (Bluefin.Internal.Examples.Application e)
+ Bluefin.Internal.Examples: instance GHC.Generics.Generic (Bluefin.Internal.Examples.Counter5 e)
+ Bluefin.Internal.Examples: instance GHC.Generics.Generic (Bluefin.Internal.Examples.Counter6 e)
+ Bluefin.Internal.Examples: instance GHC.Generics.Generic (Bluefin.Internal.Examples.FileSystem es)
+ Bluefin.Internal.OneWayCoercible: MkOneWayCoercibleD :: OneWayCoercion a b -> OneWayCoercibleD (a :: k) (b :: k)
+ Bluefin.Internal.OneWayCoercible: MkOneWayCoercion :: Coercion a b -> OneWayCoercion (a :: k) (b :: k)
+ Bluefin.Internal.OneWayCoercible: class GOneWayCoercible (a :: k) (b :: k1)
+ Bluefin.Internal.OneWayCoercible: class Generic a
+ Bluefin.Internal.OneWayCoercible: class OneWayCoercible (a :: k) (b :: k)
+ Bluefin.Internal.OneWayCoercible: gOneWayCoercible :: forall {k} h (e :: k) (es :: k). GOneWayCoercible (Rep (h e)) (Rep (h es)) => OneWayCoercibleD (h e) (h es)
+ Bluefin.Internal.OneWayCoercible: gOneWayCoercible2 :: forall {k1} {k2} h (e :: k1) (e' :: k2) (es :: k1) (es' :: k2). GOneWayCoercible (Rep (h e e')) (Rep (h es es')) => OneWayCoercibleD (h e e') (h es es')
+ Bluefin.Internal.OneWayCoercible: gOneWayCoercion :: GOneWayCoercible (Rep a) (Rep b) => OneWayCoercion a b
+ Bluefin.Internal.OneWayCoercible: instance (Bluefin.Internal.OneWayCoercible.OneWayCoercible a a', Bluefin.Internal.OneWayCoercible.OneWayCoercible b b') => Bluefin.Internal.OneWayCoercible.OneWayCoercible (a' -> b) (a -> b')
+ Bluefin.Internal.OneWayCoercible: instance (Bluefin.Internal.OneWayCoercible.OneWayCoercible a1 a2, Bluefin.Internal.OneWayCoercible.OneWayCoercible b1 b2) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (Data.Either.Either a1 b1) (Data.Either.Either a2 b2)
+ Bluefin.Internal.OneWayCoercible: instance (Bluefin.Internal.OneWayCoercible.OneWayCoercible a1 a2, Bluefin.Internal.OneWayCoercible.OneWayCoercible b1 b2) => Bluefin.Internal.OneWayCoercible.OneWayCoercible (a1, b1) (a2, b2)
+ Bluefin.Internal.OneWayCoercible: instance Bluefin.Internal.OneWayCoercible.GOneWayCoercible GHC.Generics.U1 GHC.Generics.U1
+ Bluefin.Internal.OneWayCoercible: instance Bluefin.Internal.OneWayCoercible.OneWayCoercible () ()
+ Bluefin.Internal.OneWayCoercible: instance Bluefin.Internal.OneWayCoercible.OneWayCoercible a1 a2 => Bluefin.Internal.OneWayCoercible.OneWayCoercible (GHC.Maybe.Maybe a1) (GHC.Maybe.Maybe a2)
+ Bluefin.Internal.OneWayCoercible: instance Bluefin.Internal.OneWayCoercible.OneWayCoercible c c' => Bluefin.Internal.OneWayCoercible.GOneWayCoercible (GHC.Generics.K1 i c) (GHC.Generics.K1 i' c')
+ Bluefin.Internal.OneWayCoercible: instance forall k (s :: k). Bluefin.Internal.OneWayCoercible.OneWayCoercible s s
+ Bluefin.Internal.OneWayCoercible: instance forall k1 k2 (f :: k1 -> *) (f' :: k2 -> *) (g :: k1 -> *) (g' :: k2 -> *). (Bluefin.Internal.OneWayCoercible.GOneWayCoercible f f', Bluefin.Internal.OneWayCoercible.GOneWayCoercible g g') => Bluefin.Internal.OneWayCoercible.GOneWayCoercible (f GHC.Generics.:*: g) (f' GHC.Generics.:*: g')
+ Bluefin.Internal.OneWayCoercible: instance forall k1 k2 (f :: k1 -> *) (f' :: k2 -> *) i (t :: GHC.Generics.Meta) i' (t' :: GHC.Generics.Meta). Bluefin.Internal.OneWayCoercible.GOneWayCoercible f f' => Bluefin.Internal.OneWayCoercible.GOneWayCoercible (GHC.Generics.M1 i t f) (GHC.Generics.M1 i' t' f')
+ Bluefin.Internal.OneWayCoercible: newtype OneWayCoercibleD (a :: k) (b :: k)
+ Bluefin.Internal.OneWayCoercible: newtype OneWayCoercion (a :: k) (b :: k)
+ Bluefin.Internal.OneWayCoercible: oneWayCoerce :: OneWayCoercible a b => a -> b
+ Bluefin.Internal.OneWayCoercible: oneWayCoerceWith :: OneWayCoercion a b -> a -> b
+ Bluefin.Internal.OneWayCoercible: oneWayCoercible :: forall {k} (a :: k) (b :: k). Coercible a b => OneWayCoercibleD a b
+ Bluefin.Internal.OneWayCoercible: oneWayCoercibleImpl :: OneWayCoercible a b => OneWayCoercibleD a b
+ Bluefin.Internal.OneWayCoercible: oneWayCoercion :: forall {k} (a :: k) (b :: k). OneWayCoercible a b => OneWayCoercion a b
+ Bluefin.Internal.OneWayCoercible: trans :: forall {k} (a :: k) (b :: k) (c :: k). OneWayCoercion a b -> OneWayCoercion b c -> OneWayCoercion a c
+ Bluefin.Internal.OneWayCoercible: unsafeCoercionOfOneWayCoercible :: forall {k} (a :: k) (b :: k). OneWayCoercible a b => Coercion a b
+ Bluefin.Internal.OneWayCoercible: unsafeCoercionOfOneWayCoercion :: forall {k} (a :: k) (b :: k). OneWayCoercion a b -> Coercion a b
+ Bluefin.Internal.OneWayCoercible: unsafeOneWayCoercible :: forall {k} (a :: k) (b :: k). OneWayCoercibleD a b
+ Bluefin.Internal.OneWayCoercible: unsafeOneWayCoercion :: forall {k} (a :: k) (b :: k). OneWayCoercion a b
- Bluefin.Internal.Examples: DynamicReader :: (forall (e' :: Effects). () => Eff (e' :& e) r) -> (forall (e' :: Effects) a. () => (r -> r) -> Eff e' a -> Eff (e' :& e) a) -> DynamicReader r (e :: Effects)
+ Bluefin.Internal.Examples: DynamicReader :: Eff e r -> (forall (e' :: Effects) a. () => (r -> r) -> Eff e' a -> Eff (e' :& e) a) -> DynamicReader r (e :: Effects)
- Bluefin.Internal.Examples: MkApplication :: (forall (e' :: Effects). () => String -> Int -> Eff (e' :& e) [String]) -> State (Int, Bool) e -> Stream String e -> Application (e :: Effects)
+ Bluefin.Internal.Examples: MkApplication :: (String -> Int -> Eff e [String]) -> State (Int, Bool) e -> Stream String e -> Application (e :: Effects)
- Bluefin.Internal.Examples: MkCounter5 :: (forall (e' :: Effects). () => Eff (e' :& e) ()) -> (forall (e' :: Effects). () => String -> Eff (e' :& e) Int) -> Counter5 (e :: Effects)
+ Bluefin.Internal.Examples: MkCounter5 :: Eff e () -> (String -> Eff e Int) -> Counter5 (e :: Effects)
- Bluefin.Internal.Examples: MkCounter6 :: (forall (e' :: Effects). () => Eff (e' :& e) ()) -> State Int e -> Stream String e -> Counter6 (e :: Effects)
+ Bluefin.Internal.Examples: MkCounter6 :: Eff e () -> State Int e -> Stream String e -> Counter6 (e :: Effects)
- Bluefin.Internal.Examples: MkFileSystem :: (forall (e :: Effects). () => FilePath -> Eff (e :& es) String) -> (forall (e :: Effects). () => FilePath -> String -> Eff (e :& es) ()) -> FileSystem (es :: Effects)
+ Bluefin.Internal.Examples: MkFileSystem :: (FilePath -> Eff es String) -> (FilePath -> String -> Eff es ()) -> FileSystem (es :: Effects)
- Bluefin.Internal.Examples: [askLRImpl] :: DynamicReader r (e :: Effects) -> forall (e' :: Effects). () => Eff (e' :& e) r
+ Bluefin.Internal.Examples: [askLRImpl] :: DynamicReader r (e :: Effects) -> Eff e r
- Bluefin.Internal.Examples: [getCounter5Impl] :: Counter5 (e :: Effects) -> forall (e' :: Effects). () => String -> Eff (e' :& e) Int
+ Bluefin.Internal.Examples: [getCounter5Impl] :: Counter5 (e :: Effects) -> String -> Eff e Int
- Bluefin.Internal.Examples: [incCounter5Impl] :: Counter5 (e :: Effects) -> forall (e' :: Effects). () => Eff (e' :& e) ()
+ Bluefin.Internal.Examples: [incCounter5Impl] :: Counter5 (e :: Effects) -> Eff e ()
- Bluefin.Internal.Examples: [incCounter6Impl] :: Counter6 (e :: Effects) -> forall (e' :: Effects). () => Eff (e' :& e) ()
+ Bluefin.Internal.Examples: [incCounter6Impl] :: Counter6 (e :: Effects) -> Eff e ()
- Bluefin.Internal.Examples: [queryDatabase] :: Application (e :: Effects) -> forall (e' :: Effects). () => String -> Int -> Eff (e' :& e) [String]
+ Bluefin.Internal.Examples: [queryDatabase] :: Application (e :: Effects) -> String -> Int -> Eff e [String]
- Bluefin.Internal.Examples: [readFileImpl] :: FileSystem (es :: Effects) -> forall (e :: Effects). () => FilePath -> Eff (e :& es) String
+ Bluefin.Internal.Examples: [readFileImpl] :: FileSystem (es :: Effects) -> FilePath -> Eff es String
- Bluefin.Internal.Examples: [writeFileImpl] :: FileSystem (es :: Effects) -> forall (e :: Effects). () => FilePath -> String -> Eff (e :& es) ()
+ Bluefin.Internal.Examples: [writeFileImpl] :: FileSystem (es :: Effects) -> FilePath -> String -> Eff es ()
Files
- CHANGELOG.md +6/−0
- bluefin-internal.cabal +2/−1
- src/Bluefin/Internal.hs +100/−37
- src/Bluefin/Internal/Examples.hs +37/−47
- src/Bluefin/Internal/OneWayCoercible.hs +122/−0
CHANGELOG.md view
@@ -1,3 +1,9 @@+# 0.3.0.0++* Add `Bluefin.Internal.OneWayCoercible` module and related instances++* Add `Bluefin.Internal.OneWayCoercibleHandle` and related functions+ ## 0.2.1.0 * Add `handleImpl`, `HandleD` and `handleMapHandle`
bluefin-internal.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: bluefin-internal-version: 0.2.1.0+version: 0.3.0.0 license: MIT license-file: LICENSE author: Tom Ellis@@ -86,6 +86,7 @@ Bluefin.Internal.Examples, Bluefin.Internal.Exception.Scoped, Bluefin.Internal.Key,+ Bluefin.Internal.OneWayCoercible, Bluefin.Internal.Pipes, Bluefin.Internal.System.IO
src/Bluefin/Internal.hs view
@@ -2,15 +2,26 @@ {-# LANGUAGE DerivingVia #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE RoleAnnotations #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UnliftedNewtypes #-} {-# OPTIONS_HADDOCK not-home #-} module Bluefin.Internal where import qualified Bluefin.Internal.Exception.Scoped as ScopedException+import Bluefin.Internal.OneWayCoercible+ ( OneWayCoercible (oneWayCoercibleImpl),+ OneWayCoercion,+ gOneWayCoercible,+ oneWayCoerce,+ oneWayCoerceWith,+ oneWayCoercible,+ unsafeOneWayCoercible,+ ) import qualified Control.Concurrent.Async as Async import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar) import qualified Control.Exception@@ -27,6 +38,7 @@ import Data.Proxy (Proxy (Proxy)) import Data.Type.Coercion (Coercion (Coercion)) import GHC.Exts (Proxy#, proxy#)+import GHC.Generics (Generic) import System.IO.Unsafe (unsafePerformIO) import Unsafe.Coerce (unsafeCoerce) import Prelude hiding (drop, head, read, return)@@ -40,12 +52,18 @@ type (:&) = Union -type role Eff nominal representational- newtype Eff (es :: Effects) a = UnsafeMkEff {unsafeUnEff :: IO a} deriving stock (Functor) deriving newtype (Applicative, Monad) +type role Eff nominal representational++instance (e :> es) => OneWayCoercible (Eff e) (Eff es) where+ oneWayCoercibleImpl = oneWayCoercible++instance (e :> es) => OneWayCoercible (Eff e r) (Eff es r) where+ oneWayCoercibleImpl = oneWayCoercible+ -- | Because doing 'IO' operations inside 'Eff' requires a value-level -- argument we can't give @IO@-related instances to @Eff@ directly. -- Instead we wrap it in @EffReader@.@@ -327,18 +345,30 @@ -- | Handle to an exception of type @exn@ newtype Exception exn (e :: Effects) = MkException (forall a. exn -> Eff e a)+ deriving (Handle) via OneWayCoercibleHandle (Exception exn) type role Exception representational nominal +instance (e :> es) => OneWayCoercible (Exception ex e) (Exception ex es) where+ oneWayCoercibleImpl = oneWayCoercible+ -- | A handle to a strict mutable state of type @s@ newtype State s (e :: Effects) = UnsafeMkState (IORef s)+ deriving (Handle) via OneWayCoercibleHandle (State s) type role State representational nominal +instance (e :> es) => OneWayCoercible (State s e) (State s es) where+ oneWayCoercibleImpl = oneWayCoercible+ -- | A handle to a coroutine that yields values of type @a@ and then -- expects values of type @b@. newtype Coroutine a b (e :: Effects) = MkCoroutine (a -> Eff e b)+ deriving (Handle) via OneWayCoercibleHandle (Coroutine a b) +instance (e :> es) => OneWayCoercible (Coroutine a b e) (Coroutine a b es) where+ oneWayCoercibleImpl = oneWayCoercible+ -- | A handle to a stream that yields values of type @a@. It is -- implemented as a handle to a coroutine that yields values of type -- @a@ and then expects values of type @()@.@@ -358,30 +388,15 @@ -- -- @ -- data Application e = MkApplication--- { queryDatabase :: forall e'. String -> Int -> Eff (e' :& e) [String],+-- { queryDatabase :: String -> Int -> Eff e [String], -- applicationState :: State (Int, Bool) e, -- logger :: Stream String e -- }--- @------ To define @mapHandle@ for @Application@ you should apply--- @mapHandle@ to all the fields that are themeselves handles and--- apply 'useImplUnder' to all the fields that are dynamic effects:+-- deriving (Generic)+-- deriving (Handle) via 'OneWayCoercibleHandle' Application ----- @--- instance Handle Application where--- 'handleImpl' =--- 'handleMapHandle' $--- \\MkApplication--- { queryDatabase = q,--- applicationState = a,--- logger = l--- } ->--- MkApplication--- { queryDatabase = \\s i -> 'useImplUnder' (q s i),--- applicationState = 'mapHandle' a,--- logger = mapHandle l--- }+-- instance (e :> es) => 'OneWayCoercible' (Application e) (Application es) where+-- oneWayCoercibleImpl = 'gOneWayCoercible' -- @ class Handle (h :: Effects -> Type) where {-# MINIMAL handleImpl | mapHandle #-}@@ -405,6 +420,22 @@ -- 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 -> \<definition\> -- @@@ -422,23 +453,40 @@ HandleD h handleMapHandle = MkHandleD -instance Handle (State s) where- handleImpl = handleMapHandle $ \(UnsafeMkState s) -> UnsafeMkState s+handleOneWayCoercible ::+ (forall e es. (e :> es) => OneWayCoercible (h e) (h es)) =>+ -- | ͘+ HandleD h+handleOneWayCoercible = MkHandleD oneWayCoerce -instance Handle (Exception s) where- handleImpl = handleMapHandle $ \(MkException s) ->- MkException (weakenEff has . s)+handleOneWayCoercion ::+ (forall e es. (e :> es) => OneWayCoercion (h e) (h es)) ->+ -- | ͘+ HandleD h+handleOneWayCoercion owc = MkHandleD (oneWayCoerceWith owc) -instance Handle (Coroutine a b) where- handleImpl = handleMapHandle $ \(MkCoroutine f) ->- MkCoroutine (fmap useImpl f)+-- { OneWayCoercibleHandle -instance Handle (Writer w) where- handleImpl = handleMapHandle $ \(Writer wr) -> Writer (mapHandle wr)+-- | 'OneWayCoercibleHandle' is used to derive 'Handle' instances+-- using @DerivingVia@+newtype OneWayCoercibleHandle a es = MkOneWayCoercibleHandle (a es)+ deriving stock (Generic) -instance Handle IOE where- handleImpl = handleMapHandle $ \MkIOE -> MkIOE+instance+ forall h.+ (forall e' es'. (e' :> es') => OneWayCoercible (OneWayCoercibleHandle h e') (OneWayCoercibleHandle h es')) =>+ Handle (OneWayCoercibleHandle h)+ where+ handleImpl = handleOneWayCoercible +instance+ (OneWayCoercible (h e) (h es)) =>+ OneWayCoercible (OneWayCoercibleHandle h e) (OneWayCoercibleHandle h es)+ where+ oneWayCoercibleImpl = gOneWayCoercible++-- }+ -- | A convenience type whose only purpose is to avoid writing @(# #)@ -- as an argument to functions which are only function because -- top-level definitions of unlifted kind are forbidden.@@ -1286,9 +1334,13 @@ -- | Handle that allows you to run 'IO' operations data IOE (e :: Effects) = MkIOE+ deriving (Handle) via OneWayCoercibleHandle IOE type role IOE nominal +instance (e :> es) => OneWayCoercible (IOE e) (IOE es) where+ oneWayCoercibleImpl = unsafeOneWayCoercible+ -- | Run an 'IO' operation in 'Eff' -- -- @@@ -1373,7 +1425,11 @@ Left (l, _) -> Left l newtype Writer w e = Writer (Stream w e)+ deriving (Handle) via OneWayCoercibleHandle (Writer w) +instance (e :> es) => OneWayCoercible (Writer w e) (Writer w es) where+ oneWayCoercibleImpl = oneWayCoercible+ -- | -- @ -- >>> 'Data.Monoid.getAny' $ snd $ runPureEff $ runWriter $ \\w -> do@@ -1429,6 +1485,9 @@ newtype Reader r e = MkReader (State r e) deriving newtype (Handle) +instance (e :> es) => OneWayCoercible (Reader r e) (Reader r es) where+ oneWayCoercibleImpl = oneWayCoercible+ runReader :: -- | Initial value for @Reader@. r ->@@ -1548,16 +1607,20 @@ 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 newtype ConstEffect r (e :: Effects) = MkConstEffect r+ deriving (Handle) via OneWayCoercibleHandle (ConstEffect r) +instance (e :> es) => OneWayCoercible (ConstEffect r e) (ConstEffect r es) where+ oneWayCoercibleImpl = oneWayCoercible+ runConstEffect :: r -> (forall e. ConstEffect r e -> Eff (e :& es) a) -> -- | ͘ Eff es a runConstEffect r k = useImplIn k (MkConstEffect r)--instance Handle (ConstEffect r) where- handleImpl = handleMapHandle coerce
src/Bluefin/Internal/Examples.hs view
@@ -1,9 +1,14 @@+{-# LANGUAGE DerivingVia #-} {-# LANGUAGE NoMonoLocalBinds #-} {-# LANGUAGE NoMonomorphismRestriction #-} module Bluefin.Internal.Examples where import Bluefin.Internal hiding (b, w)+import Bluefin.Internal.OneWayCoercible+ ( OneWayCoercible (oneWayCoercibleImpl),+ gOneWayCoercible,+ ) import Bluefin.Internal.Pipes ( Producer, runEffect,@@ -20,6 +25,7 @@ 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,@@ -663,22 +669,20 @@ -- Counter 5 data Counter5 e = MkCounter5- { incCounter5Impl :: forall e'. Eff (e' :& e) (),- getCounter5Impl :: forall e'. String -> Eff (e' :& e) Int+ { incCounter5Impl :: Eff e (),+ getCounter5Impl :: String -> Eff e Int }+ deriving (Generic)+ deriving (Handle) via OneWayCoercibleHandle Counter5 -instance Handle Counter5 where- handleImpl = handleMapHandle $ \c ->- MkCounter5- { incCounter5Impl = useImplUnder (incCounter5Impl c),- getCounter5Impl = \msg -> useImplUnder (getCounter5Impl c msg)- }+instance (e :> es) => OneWayCoercible (Counter5 e) (Counter5 es) where+ oneWayCoercibleImpl = gOneWayCoercible incCounter5 :: (e :> es) => Counter5 e -> Eff es ()-incCounter5 e = makeOp (incCounter5Impl (mapHandle e))+incCounter5 e = incCounter5Impl (mapHandle e) getCounter5 :: (e :> es) => Counter5 e -> String -> Eff es Int-getCounter5 e msg = makeOp (getCounter5Impl (mapHandle e) msg)+getCounter5 e msg = getCounter5Impl (mapHandle e) msg runCounter5 :: (e1 :> es) =>@@ -723,21 +727,18 @@ -- Counter 6 data Counter6 e = MkCounter6- { incCounter6Impl :: forall e'. Eff (e' :& e) (),+ { incCounter6Impl :: Eff e (), counter6State :: State Int e, counter6Stream :: Stream String e }+ deriving (Generic)+ deriving (Handle) via OneWayCoercibleHandle Counter6 -instance Handle Counter6 where- handleImpl = handleMapHandle $ \c ->- MkCounter6- { incCounter6Impl = useImplUnder (incCounter6Impl c),- counter6State = mapHandle (counter6State c),- counter6Stream = mapHandle (counter6Stream c)- }+instance (e :> es) => OneWayCoercible (Counter6 e) (Counter6 es) where+ oneWayCoercibleImpl = gOneWayCoercible incCounter6 :: (e :> es) => Counter6 e -> Eff es ()-incCounter6 e = makeOp (incCounter6Impl (mapHandle e))+incCounter6 e = incCounter6Impl (mapHandle e) getCounter6 :: (e :> es) => Counter6 e -> String -> Eff es Int getCounter6 (MkCounter6 _ st y) msg = do@@ -860,23 +861,21 @@ -- FileSystem data FileSystem es = MkFileSystem- { readFileImpl :: forall e. FilePath -> Eff (e :& es) String,- writeFileImpl :: forall e. FilePath -> String -> Eff (e :& es) ()+ { readFileImpl :: FilePath -> Eff es String,+ writeFileImpl :: FilePath -> String -> Eff es () }+ deriving (Generic)+ deriving (Handle) via OneWayCoercibleHandle FileSystem -instance Handle FileSystem where- handleImpl = handleMapHandle $ \fs ->- MkFileSystem- { readFileImpl = \fp -> useImplUnder (readFileImpl fs fp),- writeFileImpl = \fp s -> useImplUnder (writeFileImpl fs fp s)- }+instance (e :> es) => OneWayCoercible (FileSystem e) (FileSystem es) where+ oneWayCoercibleImpl = gOneWayCoercible readFile :: (e :> es) => FileSystem e -> FilePath -> Eff es String-readFile fs filepath = makeOp (readFileImpl (mapHandle fs) filepath)+readFile fs filepath = readFileImpl (mapHandle fs) filepath writeFile :: (e :> es) => FileSystem e -> FilePath -> String -> Eff es () writeFile fs filepath contents =- makeOp (writeFileImpl (mapHandle fs) filepath contents)+ writeFileImpl (mapHandle fs) filepath contents runFileSystemPure :: (e1 :> es) =>@@ -948,24 +947,15 @@ -- instance Handle example data Application e = MkApplication- { queryDatabase :: forall e'. String -> Int -> Eff (e' :& e) [String],+ { queryDatabase :: String -> Int -> Eff e [String], applicationState :: State (Int, Bool) e, logger :: Stream String e }+ deriving (Generic)+ deriving (Handle) via OneWayCoercibleHandle Application -instance Handle Application where- handleImpl =- handleMapHandle $- \MkApplication- { queryDatabase = q,- applicationState = a,- logger = l- } ->- MkApplication- { queryDatabase = \s i -> useImplUnder (q s i),- applicationState = mapHandle a,- logger = mapHandle l- }+instance (e :> es) => OneWayCoercible (Application e) (Application es) where+ oneWayCoercibleImpl = gOneWayCoercible -- This example shows a case where we can use @bracket@ polymorphically -- in order to perform correct cleanup if @es@ is instantiated to a@@ -1047,14 +1037,14 @@ Right contents -> contents data DynamicReader r e = DynamicReader- { askLRImpl :: forall e'. Eff (e' :& e) r,+ { askLRImpl :: Eff e r, localLRImpl :: forall e' a. (r -> r) -> Eff e' a -> Eff (e' :& e) a } instance Handle (DynamicReader r) where handleImpl = handleMapHandle $ \h -> DynamicReader- { askLRImpl = useImplUnder (askLRImpl h),+ { askLRImpl = useImpl (askLRImpl h), localLRImpl = \f k -> useImplUnder (localLRImpl h f k) } @@ -1062,7 +1052,7 @@ (e :> es) => DynamicReader r e -> Eff es r-askLR c = makeOp (askLRImpl (mapHandle c))+askLR c = askLRImpl (mapHandle c) localLR :: (e :> es) =>@@ -1082,7 +1072,7 @@ k DynamicReader { askLRImpl = ask h,- localLRImpl = \f k' -> makeOp (local h f (useImpl k'))+ localLRImpl = \f k' -> local h f (useImpl k') } -- Fails to compile unless '(e :> es) => e :> (x :& es)' is incoherent
+ src/Bluefin/Internal/OneWayCoercible.hs view
@@ -0,0 +1,122 @@+{-# OPTIONS_HADDOCK not-home #-}++module Bluefin.Internal.OneWayCoercible+ ( module Bluefin.Internal.OneWayCoercible,+ Generic,+ )+where++import Data.Coerce (Coercible, coerce)+import Data.Type.Coercion (Coercion (Coercion))+import GHC.Generics+import Unsafe.Coerce (unsafeCoerce)++gOneWayCoercion ::+ forall a b. (GOneWayCoercible (Rep a) (Rep b)) => OneWayCoercion a b+gOneWayCoercion = unsafeOneWayCoercion++gOneWayCoercible ::+ (GOneWayCoercible (Rep (h e)) (Rep (h es))) =>+ -- | ͘+ OneWayCoercibleD (h e) (h es)+gOneWayCoercible = MkOneWayCoercibleD gOneWayCoercion++gOneWayCoercible2 ::+ (GOneWayCoercible (Rep (h e e')) (Rep (h es es'))) =>+ OneWayCoercibleD (h e e') (h es es')+gOneWayCoercible2 = MkOneWayCoercibleD gOneWayCoercion++oneWayCoercible :: (Coercible a b) => OneWayCoercibleD a b+oneWayCoercible = MkOneWayCoercibleD (MkOneWayCoercion Coercion)++unsafeOneWayCoercion :: forall a b. OneWayCoercion a b+unsafeOneWayCoercion = MkOneWayCoercion (unsafeCoerce (Coercion @a @a))++unsafeOneWayCoercible :: forall a b. OneWayCoercibleD a b+unsafeOneWayCoercible = MkOneWayCoercibleD unsafeOneWayCoercion++newtype OneWayCoercion a b = MkOneWayCoercion (Coercion a b)++newtype OneWayCoercibleD a b = MkOneWayCoercibleD (OneWayCoercion a b)++oneWayCoercion :: (OneWayCoercible a b) => OneWayCoercion a b+oneWayCoercion = case oneWayCoercibleImpl of+ MkOneWayCoercibleD oneWay -> oneWay++oneWayCoerce :: forall a b. (OneWayCoercible a b) => a -> b+oneWayCoerce = oneWayCoerceWith (oneWayCoercion @a @b)++oneWayCoerceWith :: OneWayCoercion a b -> a -> b+oneWayCoerceWith (MkOneWayCoercion Coercion) = coerce++unsafeCoercionOfOneWayCoercion :: OneWayCoercion a b -> Coercion a b+unsafeCoercionOfOneWayCoercion (MkOneWayCoercion c) = c++unsafeCoercionOfOneWayCoercible ::+ forall a b. (OneWayCoercible a b) => Coercion a b+unsafeCoercionOfOneWayCoercible = case oneWayCoercion @a @b of+ MkOneWayCoercion c -> c++class OneWayCoercible a b where+ oneWayCoercibleImpl :: OneWayCoercibleD a b++instance {-# INCOHERENT #-} OneWayCoercible s s where+ oneWayCoercibleImpl = oneWayCoercible++instance OneWayCoercible () () where+ oneWayCoercibleImpl = oneWayCoercible++instance+ (OneWayCoercible a1 a2) =>+ OneWayCoercible (Maybe a1) (Maybe a2)+ where+ oneWayCoercibleImpl = case unsafeCoercionOfOneWayCoercible @a1 @a2 of+ Coercion -> oneWayCoercible++instance+ (OneWayCoercible a1 a2, OneWayCoercible b1 b2) =>+ OneWayCoercible (Either a1 b1) (Either a2 b2)+ where+ oneWayCoercibleImpl = case unsafeCoercionOfOneWayCoercible @a1 @a2 of+ Coercion -> case unsafeCoercionOfOneWayCoercible @b1 @b2 of+ Coercion -> oneWayCoercible++-- | Other sizes of tuples follow this pattern. We will add them when+-- someone needs them.+instance+ (OneWayCoercible a1 a2, OneWayCoercible b1 b2) =>+ OneWayCoercible (a1, b1) (a2, b2)+ where+ oneWayCoercibleImpl = case unsafeCoercionOfOneWayCoercible @a1 @a2 of+ Coercion -> case unsafeCoercionOfOneWayCoercible @b1 @b2 of+ Coercion -> oneWayCoercible++trans :: OneWayCoercion a b -> OneWayCoercion b c -> OneWayCoercion a c+trans c1 c2 = case unsafeCoercionOfOneWayCoercion c1 of+ Coercion -> case unsafeCoercionOfOneWayCoercion c2 of+ Coercion -> MkOneWayCoercion Coercion++class GOneWayCoercible a b++instance GOneWayCoercible U1 U1++instance+ (OneWayCoercible c c') =>+ GOneWayCoercible (K1 i c) (K1 i' c')++instance+ (GOneWayCoercible f f') =>+ GOneWayCoercible (M1 i t f) (M1 i' t' f')++instance+ (GOneWayCoercible f f', GOneWayCoercible g g') =>+ GOneWayCoercible (f :*: g) (f' :*: g')++instance+ (OneWayCoercible a a', OneWayCoercible b b') =>+ OneWayCoercible (a' -> b) (a -> b')+ where+ oneWayCoercibleImpl = case oneWayCoercion @a @a' of+ MkOneWayCoercion Coercion -> case oneWayCoercion @b @b' of+ MkOneWayCoercion Coercion ->+ MkOneWayCoercibleD (MkOneWayCoercion Coercion)