packages feed

bluefin-internal 0.0.6.1 → 0.0.7.0

raw patch · 5 files changed

+375/−6 lines, 5 filesdep +asyncPVP ok

version bump matches the API change (PVP)

Dependencies added: async

API changes (from Hackage documentation)

+ Bluefin.Internal: connectCoroutines :: forall es a b r. (forall e. Coroutine a b e -> Eff (e :& es) r) -> (forall e. a -> Coroutine b a e -> Eff (e :& es) r) -> Eff es r
+ Bluefin.Internal: insertManySecond :: b :> c => Eff (c1 :& b) r -> Eff (c1 :& c) r
+ Bluefin.Internal: race :: e2 :> es => (forall e. IOE e -> Eff (e :& es) a) -> (forall e. IOE e -> Eff (e :& es) a) -> IOE e2 -> Eff es a
+ Bluefin.Internal: receiveStream :: (forall e. Coroutine () a e -> Eff (e :& es) r) -> (forall e. Stream a e -> Eff (e :& es) r) -> Eff es r
+ Bluefin.Internal: unsafeProvideIO :: (forall e. IOE e -> Eff (e :& es) a) -> Eff es a
+ Bluefin.Internal: useImplWithin :: e :> es => (t -> Eff (e1 :& e) r) -> t -> Eff (e1 :& es) r
+ Bluefin.Internal: withEffToIO' :: e2 :> es => IOE e2 -> ((forall r. (forall e1. IOE e1 -> Eff (e1 :& es) r) -> IO r) -> IO a) -> Eff es a
+ Bluefin.Internal.Examples: pipesExample1 :: IO ()
+ Bluefin.Internal.Examples: pipesExample2 :: IO String
+ Bluefin.Internal.Pipes: (<-<) :: e1 :> es => (forall e. Proxy () b c' c e -> Eff (e :& es) r) -> (forall e. Proxy a' a () b e -> Eff (e :& es) r) -> Proxy a' a c' c e1 -> Eff es r
+ Bluefin.Internal.Pipes: (<~) :: e1 :> es => (b -> forall e. Proxy x' x c' c e -> Eff (e :& es) b') -> (a -> forall e. Proxy x' x b' b e -> Eff (e :& es) a') -> a -> Proxy x' x c' c e1 -> Eff es a'
+ Bluefin.Internal.Pipes: (>->) :: e1 :> es => (forall e. Proxy a' a () b e -> Eff (e :& es) r) -> (forall e. Proxy () b c' c e -> Eff (e :& es) r) -> Proxy a' a c' c e1 -> Eff es r
+ Bluefin.Internal.Pipes: (>~) :: e1 :> es => (forall e. Proxy a' a y' y e -> Eff (e :& es) b) -> (forall e. Proxy () b y' y e -> Eff (e :& es) c) -> Proxy a' a y' y e1 -> Eff es c
+ Bluefin.Internal.Pipes: (~<) :: e1 :> es => (forall e. Proxy () b y' y e -> Eff (e :& es) c) -> (forall e. Proxy a' a y' y e -> Eff (e :& es) b) -> Proxy a' a y' y e1 -> Eff es c
+ Bluefin.Internal.Pipes: (~>) :: e1 :> es => (a -> forall e. Proxy x' x b' b e -> Eff (e :& es) a') -> (b -> forall e. Proxy x' x c' c e -> Eff (e :& es) b') -> a -> Proxy x' x c' c e1 -> Eff es a'
+ Bluefin.Internal.Pipes: MkProxy :: Coroutine a' a e -> Coroutine b b' e -> Proxy a' a b' b e
+ Bluefin.Internal.Pipes: await :: e :> es => Proxy () a y' y e -> Eff es a
+ Bluefin.Internal.Pipes: cat :: Pipe a a e -> Eff (e :& es) r
+ Bluefin.Internal.Pipes: data Proxy a' a b' b e
+ Bluefin.Internal.Pipes: drain :: e :> es => Proxy () b c' c e -> Eff es r
+ Bluefin.Internal.Pipes: each :: Foldable f => f a -> Proxy x' x () a e -> Eff (e :& es) ()
+ Bluefin.Internal.Pipes: for :: e1 :> es => (forall e. Proxy x' x b' b e -> Eff (e :& es) a') -> (b -> forall e. Proxy x' x c' c e -> Eff (e :& es) b') -> Proxy x' x c' c e1 -> Eff es a'
+ Bluefin.Internal.Pipes: infixl 4 <~
+ Bluefin.Internal.Pipes: infixl 5 >~
+ Bluefin.Internal.Pipes: infixl 7 >->
+ Bluefin.Internal.Pipes: infixr 4 ~>
+ Bluefin.Internal.Pipes: infixr 5 ~<
+ Bluefin.Internal.Pipes: infixr 7 <-<
+ Bluefin.Internal.Pipes: map :: e :> es => (a -> b) -> Pipe a b e -> Eff es r
+ Bluefin.Internal.Pipes: mapM :: e :> es => (a -> Eff es b) -> Pipe a b e -> Eff es r
+ Bluefin.Internal.Pipes: mapM_ :: e :> es => (a -> Eff es ()) -> Proxy () a b b' e -> Eff es r
+ Bluefin.Internal.Pipes: next :: ()
+ Bluefin.Internal.Pipes: print :: (e2 :> es, e1 :> es, Show a) => IOE e1 -> Consumer a e2 -> Eff es r
+ Bluefin.Internal.Pipes: repeatM :: e :> es => Eff es a -> Proxy x' x () a e -> Eff es r
+ Bluefin.Internal.Pipes: replicateM :: e :> es => Int -> Eff es a -> Proxy x' x () a e -> Eff es ()
+ Bluefin.Internal.Pipes: reverseProxy :: Proxy a' a b' b e -> Proxy b b' a a' e
+ Bluefin.Internal.Pipes: runEffect :: (forall e. Effect e -> Eff (e :& es) r) -> Eff es r
+ Bluefin.Internal.Pipes: stdinLn :: (e1 :> es, e2 :> es) => IOE e1 -> Producer String e2 -> Eff es r
+ Bluefin.Internal.Pipes: stdoutLn :: (e1 :> es, e2 :> es) => IOE e1 -> Consumer String e2 -> Eff es r
+ Bluefin.Internal.Pipes: takeWhile' :: e :> es => (r -> Bool) -> Pipe r r e -> Eff es r
+ Bluefin.Internal.Pipes: type Consumer a = Pipe a Void
+ Bluefin.Internal.Pipes: type Effect = Producer Void
+ Bluefin.Internal.Pipes: type Pipe a = Proxy () a ()
+ Bluefin.Internal.Pipes: type Producer = Proxy Void () ()
+ Bluefin.Internal.Pipes: unfoldr :: e :> es => (s -> Eff es (Either r (a, s))) -> s -> Proxy x1 x () a e -> Eff es r
+ Bluefin.Internal.Pipes: yield :: e :> es => Proxy x1 x () a e -> a -> Eff es ()

Files

CHANGELOG.md view
@@ -1,3 +1,9 @@+## 0.0.7.0++Add `withEffToIO'`, `race`, `connectCoroutines`, `receiveStream`,+`insertManySecond`, `useImplWithin`, `unsafeProvideIO`, and+`Bluefin.Internal.Pipes`+ ## 0.0.6.1  * Documentation improvements
bluefin-internal.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               bluefin-internal-version:            0.0.6.1+version:            0.0.7.0 license:            MIT license-file:       LICENSE author:             Tom Ellis@@ -77,6 +77,7 @@     default-language: Haskell2010     hs-source-dirs: src     build-depends:+      async,       base >= 4.12 && < 4.21,       unliftio-core < 0.3,       transformers < 0.7,@@ -85,7 +86,8 @@     ghc-options: -Wall     exposed-modules:       Bluefin.Internal,-      Bluefin.Internal.Examples+      Bluefin.Internal.Examples,+      Bluefin.Internal.Pipes  test-suite bluefin-test     import:           defaults
src/Bluefin/Internal.hs view
@@ -9,6 +9,8 @@  module Bluefin.Internal where +import qualified Control.Concurrent.Async as Async+import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar) import Control.Exception (throwIO, tryJust) import qualified Control.Exception import Control.Monad.Base (MonadBase (liftBase))@@ -64,6 +66,14 @@   Eff es a withEffToIO k io = effIO io (k (\f -> unsafeUnEff (f MkIOE))) +withEffToIO' ::+  (e2 :> es) =>+  -- | Continuation with the unlifting function in scope.+  IOE e2 ->+  ((forall r. (forall e1. IOE e1 -> Eff (e1 :& es) r) -> IO r) -> IO a) ->+  Eff es a+withEffToIO' io k = withEffToIO k io+ -- We don't try to do anything sophisticated here.  I haven't thought -- through all the consequences. instance (e :> es) => MonadUnliftIO (EffReader (IOE e) es) where@@ -86,6 +96,53 @@             )       ) +race ::+  (e2 :> es) =>+  (forall e. IOE e -> Eff (e :& es) a) ->+  (forall e. IOE e -> Eff (e :& es) a) ->+  IOE e2 ->+  Eff es a+race x y io = do+  r <- withEffToIO' io $ \toIO ->+    Async.race (toIO x) (toIO y)++  pure $ case r of+    Left a -> a+    Right a -> a++-- | Connect two coroutines.  Their execution is interleaved by+-- exchanging @a@s and @b@s. When the first yields its first @a@ it+-- starts the second (which is waiting to receive an @a@).+connectCoroutines ::+  forall es a b r.+  (forall e. Coroutine a b e -> Eff (e :& es) r) ->+  (forall e. a -> Coroutine b a e -> Eff (e :& es) r) ->+  -- | ͘+  Eff es r+connectCoroutines m1 m2 = unsafeProvideIO $ \io -> do+  av <- effIO io newEmptyMVar+  bv <- effIO io newEmptyMVar++  let t1 :: forall e. IOE e -> Eff (e :& es) r+      t1 io' = forEach (useImplWithin m1) $ \a -> effIO io' $ do+        putMVar av a+        takeMVar bv++  let t2 :: forall e. IOE e -> Eff (e :& es) r+      t2 io' = do+        ainit <- effIO io' (takeMVar av)+        forEach (useImplWithin (m2 ainit)) $ \b_ -> effIO io' $ do+          putMVar bv b_+          takeMVar av++  race (useImplWithin t1) (useImplWithin t2) io++receiveStream ::+  (forall e. Coroutine () a e -> Eff (e :& es) r) ->+  (forall e. Stream a e -> Eff (e :& es) r) ->+  Eff es r+receiveStream r s = connectCoroutines r (\() -> s)+ instance (e :> es) => MonadBase IO (EffReader (IOE e) es) where   liftBase = liftIO @@ -159,6 +216,9 @@ insertSecond :: Eff (c1 :& b) r -> Eff (c1 :& (c2 :& b)) r insertSecond = weakenEff (b (drop (eq (# #)))) +insertManySecond :: (b :> c) => Eff (c1 :& b) r -> Eff (c1 :& c) r+insertManySecond = weakenEff (bimap has has)+ assoc1Eff :: Eff ((a :& b) :& c) r -> Eff (a :& (b :& c)) r assoc1Eff = weakenEff (assoc1 (# #)) @@ -184,6 +244,15 @@   Eff es r useImplIn f h = inContext (f h) +-- | Like 'useImplIn'+useImplWithin ::+  (e :> es) =>+  (t -> Eff (e1 :& e) r) ->+  t ->+  -- | ͘+  Eff (e1 :& es) r+useImplWithin k fsh = insertManySecond (k fsh)+ -- | Handle to a capability to create strict mutable state handles data StateSource (e :: Effects) = StateSource @@ -193,13 +262,13 @@ -- | A handle to a strict mutable state of type @s@ newtype State s (e :: Effects) = UnsafeMkState (IORef s) --- | A handle to a coroutine that expects values of type @a@ and then--- yields values of type @b@.+-- | 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)  -- | A handle to a stream that yields values of type @a@.  It is--- implemented as a handle to a coroutine that expects values of type--- @()@ and then yields values of type @a@.+-- implemented as a handle to a coroutine that yields values of type+-- @a@ and then expects values of type @()@. type Stream a = Coroutine a ()  -- | You can define a @Handle@ instance for your compound handles.  As@@ -955,6 +1024,12 @@   -- | ͘   IO a runEff eff = unsafeUnEff (eff MkIOE)++unsafeProvideIO ::+  (forall e. IOE e -> Eff (e :& es) a) ->+  -- | ͘+  Eff es a+unsafeProvideIO eff = unsafeRemoveEff (eff MkIOE)  connect ::   (forall e1. Coroutine a b e1 -> Eff (e1 :& es) r1) ->
src/Bluefin/Internal/Examples.hs view
@@ -4,6 +4,15 @@ module Bluefin.Internal.Examples where  import Bluefin.Internal hiding (w)+import Bluefin.Internal.Pipes+  ( Producer,+    runEffect,+    stdinLn,+    stdoutLn,+    takeWhile',+    (>->),+  )+import qualified Bluefin.Internal.Pipes as P import Control.Exception (IOException) import qualified Control.Exception import Control.Monad (forever, unless, when)@@ -646,3 +655,13 @@   runPureEff $ do     (_res, st) <- runState (0, False) $ \st -> try $ \e -> polymorphicBracket st (throw e 42)     pure st++pipesExample1 :: IO ()+pipesExample1 = runEff $ \io -> runEffect (count >-> P.print io)+  where+    count :: (e :> es) => Producer Int e -> Eff es ()+    count p = for_ [1 .. 5] $ \i -> P.yield p i++pipesExample2 :: IO String+pipesExample2 = runEff $ \io -> runEffect $ do+  stdinLn io >-> takeWhile' (/= "quit") >-> stdoutLn io
+ src/Bluefin/Internal/Pipes.hs view
@@ -0,0 +1,267 @@+module Bluefin.Internal.Pipes where++import Bluefin.Internal hiding (yield)+import qualified Bluefin.Internal+import Control.Monad (forever)+import Data.Foldable (for_)+import Data.Void (Void, absurd)+import Prelude hiding (break, print, takeWhile)+import qualified Prelude++data Proxy a' a b' b e = MkProxy (Coroutine a' a e) (Coroutine b b' e)++type Pipe a = Proxy () a ()++type Producer = Proxy Void () ()++type Consumer a = Pipe a Void++type Effect = Producer Void++infixl 7 >->++(>->) ::+  (e1 :> es) =>+  (forall e. Proxy a' a () b e -> Eff (e :& es) r) ->+  (forall e. Proxy () b c' c e -> Eff (e :& es) r) ->+  Proxy a' a c' c e1 ->+  -- | ͘+  Eff es r+(>->) k1 k2 (MkProxy c1 c2) =+  receiveStream+    (\c -> useImplIn k2 (MkProxy (mapHandle c) (mapHandle c2)))+    (\s -> useImplIn k1 (MkProxy (mapHandle c1) (mapHandle s)))++infixr 7 <-<++(<-<) ::+  (e1 :> es) =>+  (forall e. Proxy () b c' c e -> Eff (e :& es) r) ->+  (forall e. Proxy a' a () b e -> Eff (e :& es) r) ->+  Proxy a' a c' c e1 ->+  -- | ͘+  Eff es r+k1 <-< k2 = k2 >-> k1++for ::+  (e1 :> es) =>+  (forall e. Proxy x' x b' b e -> Eff (e :& es) a') ->+  (b -> forall e. Proxy x' x c' c e -> Eff (e :& es) b') ->+  Proxy x' x c' c e1 ->+  -- | ͘+  Eff es a'+for k1 k2 (MkProxy c1 c2) =+  forEach (\bk -> useImplIn k1 (MkProxy (mapHandle c1) (mapHandle bk))) $ \b_ ->+    useImplIn (k2 b_) (MkProxy (mapHandle c1) (mapHandle c2))++infixr 4 ~>++(~>) ::+  (e1 :> es) =>+  (a -> forall e. Proxy x' x b' b e -> Eff (e :& es) a') ->+  (b -> forall e. Proxy x' x c' c e -> Eff (e :& es) b') ->+  a ->+  Proxy x' x c' c e1 ->+  -- | ͘+  Eff es a'+(k1 ~> k2) a = for (k1 a) k2++infixl 4 <~++(<~) ::+  (e1 :> es) =>+  (b -> forall e. Proxy x' x c' c e -> Eff (e :& es) b') ->+  (a -> forall e. Proxy x' x b' b e -> Eff (e :& es) a') ->+  a ->+  Proxy x' x c' c e1 ->+  -- | ͘+  Eff es a'+k2 <~ k1 = k1 ~> k2++reverseProxy :: Proxy a' a b' b e -> Proxy b b' a a' e+reverseProxy (MkProxy c1 c2) = MkProxy c2 c1++infixl 5 >~++(>~) ::+  (e1 :> es) =>+  (forall e. Proxy a' a y' y e -> Eff (e :& es) b) ->+  (forall e. Proxy () b y' y e -> Eff (e :& es) c) ->+  Proxy a' a y' y e1 ->+  -- | ͘+  Eff es c+(>~) k1 k2 p =+  for+    ( \p1 ->+        k2 (reverseProxy p1)+    )+    (\() p1 -> k1 (reverseProxy p1))+    (reverseProxy p)++infixr 5 ~<++(~<) ::+  (e1 :> es) =>+  (forall e. Proxy () b y' y e -> Eff (e :& es) c) ->+  (forall e. Proxy a' a y' y e -> Eff (e :& es) b) ->+  Proxy a' a y' y e1 ->+  -- | ͘+  Eff es c+(~<) k1 k2 = (>~) k2 k1++cat :: Pipe a a e -> Eff (e :& es) r+cat (MkProxy c1 c2) = forever $ do+  a <- yieldCoroutine c1 ()+  yieldCoroutine c2 a++runEffect ::+  (forall e. Effect e -> Eff (e :& es) r) ->+  -- | ͘+  Eff es r+runEffect k =+  forEach+    ( \c1 ->+        forEach+          ( \c2 ->+              useImplIn+                k+                (MkProxy (mapHandle c1) (mapHandle c2))+          )+          absurd+    )+    absurd++yield ::+  (e :> es) =>+  Proxy x1 x () a e ->+  a ->+  -- | ͘+  Eff es ()+yield (MkProxy _ c) = Bluefin.Internal.yield c++await :: (e :> es) => Proxy () a y' y e -> Eff es a+await (MkProxy c _) = yieldCoroutine c ()++-- | @pipe@'s 'next' doesn't exist in Bluefin+next :: ()+next = ()++each ::+  (Foldable f) =>+  f a ->+  Proxy x' x () a e ->+  -- | ͘+  Eff (e :& es) ()+each f p = for_ f (yield p)++repeatM ::+  (e :> es) =>+  Eff es a ->+  Proxy x' x () a e ->+  -- | ͘+  Eff es r+repeatM e p = forever $ do+  a <- e+  yield p a++replicateM ::+  (e :> es) =>+  Int ->+  Eff es a ->+  Proxy x' x () a e ->+  -- | ͘+  Eff es ()+replicateM n e p = for_ [0 .. n] $ \_ -> do+  a <- e+  yield p a++print ::+  (e2 :> es, e1 :> es, Show a) =>+  IOE e1 ->+  Consumer a e2 ->+  -- | ͘+  Eff es r+print io p = forever $ do+  a <- await p+  effIO io (Prelude.print a)++unfoldr ::+  (e :> es) =>+  (s -> Eff es (Either r (a, s))) ->+  s ->+  Proxy x1 x () a e ->+  -- | ͘+  Eff es r+unfoldr next_ sInit p =+  withEarlyReturn $ \break -> evalState sInit $ \ss -> forever $ do+    s <- get ss+    useImpl (next_ s) >>= \case+      Left r -> returnEarly break r+      Right (a, s') -> do+        put ss s'+        yield p a++mapM_ ::+  (e :> es) =>+  (a -> Eff es ()) ->+  Proxy () a b b' e ->+  -- | ͘+  Eff es r+mapM_ f = for cat (\a _ -> useImpl (f a))++drain ::+  (e :> es) =>+  Proxy () b c' c e ->+  -- | ͘+  Eff es r+drain = for cat (\_ _ -> pure ())++map ::+  (e :> es) =>+  (a -> b) ->+  Pipe a b e ->+  -- | ͘+  Eff es r+map f = for cat (\a p1 -> yield p1 (f a))++mapM ::+  (e :> es) =>+  (a -> Eff es b) ->+  Pipe a b e ->+  -- | ͘+  Eff es r+mapM f = for cat $ \a p -> do+  b_ <- useImpl (f a)+  yield p b_++takeWhile' ::+  (e :> es) =>+  (r -> Bool) ->+  Pipe r r e ->+  -- | ͘+  Eff es r+takeWhile' predicate p = withEarlyReturn $ \early -> forever $ do+  a <- await p+  if predicate a+    then yield p a+    else returnEarly early a++stdinLn ::+  (e1 :> es, e2 :> es) =>+  IOE e1 ->+  Producer String e2 ->+  -- | ͘+  Eff es r+stdinLn io c = forever $ do+  line <- effIO io getLine+  yield c line++stdoutLn ::+  (e1 :> es, e2 :> es) =>+  IOE e1 ->+  Consumer String e2 ->+  -- | ͘+  Eff es r+stdoutLn io c = forever $ do+  line <- await c+  effIO io (putStrLn line)