incipit-0.4.0.0: A Prelude for Polysemy
Safe HaskellSafe-Inferred
LanguageHaskell2010

Incipit.Full

Description

A Prelude for Polysemy projects, reexporting names and modules from several basic libraries.

Synopsis

Documentation

type EventConsumer e = Scoped_ (Consume e) #

Convenience alias for the consumer effect.

runConc :: Sem ConcStack a -> IO a #

Interprets UninterruptibleMask, Mask and Race in terms of Final IO and runs the entire rest of the stack.

type ScopedSync a = Scoped_ (Sync a) #

Convenience alias.

data Sync d (a :: Type -> Type) b #

Abstracts an MVar.

For documentation on the constructors, see the module Polysemy.Conc.Effect.Sync.

import Polysemy.Conc (Sync)
import qualified Polysemy.Conc.Effect.Sync as Sync

prog :: Member (Sync Int) r => Sem r Int
prog = do
  Sync.putTry 5
  Sync.takeBlock

subscribe :: forall e (r :: EffectRow). Member (Scoped_ (Consume e)) r => InterpreterFor (Consume e) r #

Create a new scope for Events, causing the nested program to get its own copy of the event stream. To be used with interpretEventsChan.

consume :: forall e (r :: EffectRow). Member (Consume e) r => Sem r e #

Consume one event emitted by Events.

publish :: forall e (r :: EffectRow). Member (Events e) r => e -> Sem r () #

Publish one event.

data Events e (a :: Type -> Type) b #

An event publisher that can be consumed from multiple threads.

type Mask = Scoped_ RestoreMask #

The scoped masking effect.

type UninterruptibleMask = Scoped_ RestoreMask #

The scoped uninterruptible masking effect.

scoped_ :: forall (effect :: Effect) (r :: EffectRow). Member (Scoped_ effect) r => InterpreterFor effect r #

Constructor for Scoped_, taking a nested program and transforming all instances of effect to Scoped_ effect.

Please consult the documentation of Scoped for details and examples.

scoped :: forall param (effect :: Effect) (r :: EffectRow). Member (Scoped param effect) r => param -> InterpreterFor effect r #

Constructor for Scoped, taking a nested program and transforming all instances of effect to Scoped param effect.

Please consult the documentation of Scoped for details and examples.

data Scoped param (effect :: Effect) (a :: Type -> Type) b #

Scoped transforms a program so that an interpreter for effect may perform arbitrary actions, like resource management, before and after the computation wrapped by a call to scoped is executed.

Note: This effect has been merged to Polysemy and will be released there soon.

An application for this is Polysemy.Conc.Events from https://hackage.haskell.org/package/polysemy-conc, in which each program using the effect Polysemy.Conc.Consume is interpreted with its own copy of the event channel; or a database transaction, in which a transaction handle is created for the wrapped program and passed to the interpreter for the database effect.

For a longer exposition, see https://www.tweag.io/blog/2022-01-05-polysemy-scoped/. Note that the interface has changed since the blog post was published: The resource parameter no longer exists.

Resource allocation is performed by a function passed to interpretScoped.

The constructors are not intended to be used directly; the smart constructor scoped is used like a local interpreter for effect. scoped takes an argument of type param, which will be passed through to the interpreter, to be used by the resource allocation function.

As an example, imagine an effect for writing lines to a file:

data Write :: Effect where
  Write :: Text -> Write m ()
makeSem ''Write

If we now have the following requirements:

  1. The file should be opened and closed right before and after the part of the program in which we write lines
  2. The file name should be specifiable at the point in the program where writing begins
  3. We don't want to commit to IO, lines should be stored in memory when running tests

Then we can take advantage of Scoped to write this program:

prog :: Member (Scoped FilePath Write) r => Sem r ()
prog = do
  scoped "file1.txt" do
    write "line 1"
    write "line 2"
  scoped "file2.txt" do
    write "line 1"
    write "line 2"

Here scoped creates a prompt for an interpreter to start allocating a resource for "file1.txt" and handling Write actions using that resource. When the scoped block ends, the resource should be freed.

The interpreter may look like this:

interpretWriteFile :: Members '[Resource, Embed IO] => InterpreterFor (Scoped FilePath Write) r
interpretWriteFile =
  interpretScoped allocator handler
  where
    allocator name use = bracket (openFile name WriteMode) hClose use
    handler fileHandle (Write line) = embed (Text.hPutStrLn fileHandle line)

Essentially, the bracket is executed at the point where scoped was called, wrapping the following block. When the second scoped is executed, another call to bracket is performed.

The effect of this is that the operation that uses Embed IO was moved from the call site to the interpreter, while the interpreter may be executed at the outermost layer of the app.

This makes it possible to use a pure interpreter for testing:

interpretWriteOutput :: Member (Output (FilePath, Text)) r => InterpreterFor (Scoped FilePath Write) r
interpretWriteOutput =
  interpretScoped (\ name use -> use name) \ name -> \case
    Write line -> output (name, line)

Here we simply pass the name to the interpreter in the resource allocation function.

Now imagine that we drop requirement 2 from the initial list – we still want the file to be opened and closed as late/early as possible, but the file name is globally fixed. For this case, the param type is unused, and the API provides some convenience aliases to make your code more concise:

prog :: Member (Scoped_ Write) r => Sem r ()
prog = do
  scoped_ do
    write "line 1"
    write "line 2"
  scoped_ do
    write "line 1"
    write "line 2"

The type Scoped_ and the constructor scoped_ simply fix param to ().

type Scoped_ (effect :: Effect) = Scoped () effect #

A convenience alias for a scope without parameters.

data Race (a :: Type -> Type) b #

Abstract the concept of running two programs concurrently, aborting the other when one terminates. Timeout is a simpler variant, where one thread just sleeps for a given interval.

data Queue d (a :: Type -> Type) b #

Abstracts queues like TBQueue.

For documentation on the constructors, see the module Polysemy.Conc.Data.Queue.

import Polysemy.Conc (Queue, QueueResult)
import Polysemy.Conc.Effect.Queue as Queue

prog :: Member (Queue Int) r => Sem r (QueueResult Int)
prog = do
  Queue.write 5
  Queue.write 10
  Queue.read >>= \case
    QueueResult.Success i -> fmap (i +) <$> Queue.read
    r -> pure r

data Interrupt (a :: Type -> Type) b #

The interrupt handler effect allows three kinds of interaction for interrupt signals:

  • Execute a callback when a signal is received
  • Block a thread until a signal is received
  • Kill a thread when a signal is received

For documentation on the constructors, see the module Polysemy.Conc.Effect.Interrupt.

import qualified Polysemy.Conc.Effect.Interrupt as Interrupt

prog = do
  Interrupt.register "task 1" (putStrLn "interrupted")
  Interrupt.killOnQuit $ forever do
   doSomeWork

data QueueResult d #

Encodes failure reasons for queues.

For documentation on the constructors, see the module Polysemy.Conc.Data.QueueResult.

import qualified Polysemy.Conc.Data.QueueResult as QueueResult

Instances

Instances details
Functor QueueResult 
Instance details

Defined in Polysemy.Conc.Data.QueueResult

Methods

fmap :: (a -> b) -> QueueResult a -> QueueResult b #

(<$) :: a -> QueueResult b -> QueueResult a #

Monoid d => Monoid (QueueResult d) 
Instance details

Defined in Polysemy.Conc.Data.QueueResult

Semigroup d => Semigroup (QueueResult d) 
Instance details

Defined in Polysemy.Conc.Data.QueueResult

Generic (QueueResult d) 
Instance details

Defined in Polysemy.Conc.Data.QueueResult

Associated Types

type Rep (QueueResult d) :: Type -> Type #

Methods

from :: QueueResult d -> Rep (QueueResult d) x #

to :: Rep (QueueResult d) x -> QueueResult d #

Show d => Show (QueueResult d) 
Instance details

Defined in Polysemy.Conc.Data.QueueResult

Eq d => Eq (QueueResult d) 
Instance details

Defined in Polysemy.Conc.Data.QueueResult

Ord d => Ord (QueueResult d) 
Instance details

Defined in Polysemy.Conc.Data.QueueResult

type Rep (QueueResult d) 
Instance details

Defined in Polysemy.Conc.Data.QueueResult

type Rep (QueueResult d) = D1 ('MetaData "QueueResult" "Polysemy.Conc.Data.QueueResult" "polysemy-conc-0.10.0.0-8XktqGSz2QIF0jJVXBKBW3" 'False) (C1 ('MetaCons "Success" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 d)) :+: (C1 ('MetaCons "NotAvailable" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Closed" 'PrefixI 'False) (U1 :: Type -> Type)))

data Log (a :: Type -> Type) b #

The default high-level effect for simple text messages. To be used with the severity constructors:

import qualified Polysemy.Log as Log

prog = do
  Log.debug "debugging…"
  Log.warn "warning!"

Interpreters should preprocess and relay the message to DataLog.

data DataLog a (b :: Type -> Type) c #

Structural logs, used as a backend for the simpler Text log effect, Log.

Can also be used on its own, or reinterpreted into an effect like those from co-log or di.

class TimeUnit u #

Types that represent an amount of time that can be converted to each other. The methods are internal, the API function is convert.

Minimal complete definition

nanos

Instances

Instances details
TimeUnit Days 
Instance details

Defined in Polysemy.Time.Data.TimeUnit

TimeUnit Hours 
Instance details

Defined in Polysemy.Time.Data.TimeUnit

TimeUnit MicroSeconds 
Instance details

Defined in Polysemy.Time.Data.TimeUnit

TimeUnit MilliSeconds 
Instance details

Defined in Polysemy.Time.Data.TimeUnit

TimeUnit Minutes 
Instance details

Defined in Polysemy.Time.Data.TimeUnit

TimeUnit NanoSeconds 
Instance details

Defined in Polysemy.Time.Data.TimeUnit

TimeUnit Seconds 
Instance details

Defined in Polysemy.Time.Data.TimeUnit

TimeUnit Weeks 
Instance details

Defined in Polysemy.Time.Data.TimeUnit

TimeUnit DiffTime 
Instance details

Defined in Polysemy.Time.Data.TimeUnit

TimeUnit NominalDiffTime 
Instance details

Defined in Polysemy.Time.Data.TimeUnit

data Time time date (a :: Type -> Type) b #

The Time effect.