packages feed

heftia-effects-0.5.0.0: Example/UnliftIO/Main.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}

-- SPDX-License-Identifier: MPL-2.0

module Main where

import Control.Applicative ((<|>))
import Control.Arrow ((>>>))
import Control.Monad.Hefty (
    Eff,
    Type,
    interpret,
    interpretH,
    liftIO,
    makeEffectF,
    makeEffectH,
    raiseAllH,
    type (<<|),
    type (<|),
    type (~>),
 )
import Control.Monad.Hefty.Coroutine (Status (Continue, Done), runCoroutine, yield_)
import Control.Monad.Hefty.NonDet (runChooseH, runNonDetMonoid)
import Control.Monad.Hefty.Resource (runResourceIO)
import Control.Monad.Hefty.Unlift (runUnliftIO)
import Data.Effect.Resource (Resource, bracket_)

data DBF (a :: Type) where
    InsertDB :: Int -> DBF ()
makeEffectF [''DBF]

data DBH m (a :: Type) where
    Transact :: m a -> DBH m a
makeEffectH [''DBH]

runDummyDB :: (Resource <<| eh, IO <| ef) => Eff (DBH ': eh) (DBF ': ef) ~> Eff eh ef
runDummyDB =
    interpretH \case
        Transact m ->
            bracket_
                (liftIO $ putStrLn "[DummyDB] Start transaction.")
                (liftIO $ putStrLn "[DummyDB] End transaction.")
                m
        >>> interpret \case
            InsertDB x -> liftIO $ putStrLn $ "[DummyDB] insertDB " <> show x

main :: IO ()
main =
    runUnliftIO . runResourceIO . runDummyDB $ do
        insertDB 42

        transact do
            insertDB 123
            insertDB 456

            raiseAllH do
                -- Even within the scope of UnliftIO, you can combine
                -- non-deterministic computations...
                runNonDetMonoid (const $ pure ()) . runChooseH $ do
                    insertDB 1 <|> insertDB 2

                -- ...or even use coroutines.
                do
                    status <- runCoroutine do
                        yield_ @Int $ -10
                        insertDB $ -20

                    case status of
                        Done () -> pure ()
                        Continue x resume -> do
                            _ <- resume ()
                            insertDB x
                            pure ()

                -- Note that UnliftIO is disabled within the scope of 'raiseAllH'.
                -- Fitst-order 'IO' operations are still possible.
                liftIO $ putStrLn "The transaction is being finalized..."

        insertDB 789

{-
[DummyDB] insertDB 42
[DummyDB] Start transaction.
[DummyDB] insertDB 123
[DummyDB] insertDB 456
[DummyDB] insertDB 1
[DummyDB] insertDB 2
[DummyDB] insertDB -20
[DummyDB] insertDB -10
The transaction is being finalized...
[DummyDB] End transaction.
[DummyDB] insertDB 789
-}