HORIZON HASKELLDocslts/ghc-10.0.x8fef28d2026-11-02Search packagesCtrl K
Theme: |

GHC 10.0.0.20260917 · lts/ghc-10.0.x · 8fef28d · 2026-11-02

Modulepolysemy-zoo-0.8.2.0Haskell2010

Polysemy.Operators

Operators meant as replacements for traditional Sem type and Member / Members constraints, that allow you to specify types of your actions and interpreters in more concise way, without mentioning unnecessary details:

foo :: Member (Embed IO) r => String -> Int -> Sem r ()

can be written simply as:

foo :: String -> Int -> IO ~@> ()

Working example with operators:

import Data.Function
import Polysemy
import Polysemy.Operators
import Polysemy.Random

data ConsoleIO m a where
  WriteStrLn ::           String -> ConsoleIO m ()
  ReadStrLn  ::                     ConsoleIO m String
  ShowStrLn  :: Show a => a      -> ConsoleIO m ()

makeSem ''ConsoleIO

-- runConsoleIO :: Member (Embed IO) r => Sem (ConsoleIO : r) a -> Sem r a
runConsoleIO :: ConsoleIO : r @> a -> IO ~@ r @> a
runConsoleIO = interpret \case
  WriteStrLn s -> sendM $ putStrLn s
  ReadStrLn    -> sendM   getLine
  ShowStrLn  v -> sendM $ print v

main :: IO ()
main = program
     & runConsoleIO
     & runRandomIO
     & runM

-- program :: Members '[Random, ConsoleIO] r => Sem r ()
program :: '[Polysemy.Random, ConsoleIO] >@> ()
program = do
  writeStrLn "It works! Write something:"
  val <- readStrLn
  writeStrLn $ "Here it is!: " ++ val
  num <- random @Int
  writeStrLn $ "Some random number:"
  showStrLn num

Please keep in mind that constraints created through these operators are limited to the action they are being used on, for example:

foo :: (forall x. r @> x -> IO x)
    -> IO (forall a. Foo : r @> a -> IO ~@ r @> a)

The first argument in the signature above won't have access to the (IO ~@) constraint in the result - in such cases, use a normal constraint instead:

foo :: Member (Embed IO) r
    => (forall x. r @> x -> IO x)
    -> IO (forall a. Foo : r @> a -> r @> a)

See the documentation of specific operators for more details.

Contents
  1. Sem operators
  2. Member operators
  3. Combined operators
Synopsis

Sem operators

Infix equivalents of Sem with versions for specifiying list of effects (@>), single effect (@-) and single monad (@~) as effects of union. Use (>@>), (-@>) or (~@>) instead if you are not making any transformations on union and just want to use some members instead.

Examples:

Sem with list of multiple effects:

foo :: Sem (State Int : r) ()

can be written as:

foo :: State Int : r @> ()

Sem with list of one effect:

foo :: Sem '[State Int] ()

can be written as both (with the latter preferred):

foo :: '[State Int] @> ()

and:

foo :: State Int @- ()

where effect without list gets put into one automatically.

Sem with exactly one, lifted monad:

foo :: Sem '[Embed IO] ()

can be written simply as:

foo :: IO @~ ()

and will be automatically lifted and put into list.

Member operators

Infix equivalents of Member(s) constraint used directly in return type, specifiying list of members (>@), single member (-@) or single monad (~@), meant to be paired with some of the Sem operators ((@>), (@-) and (@~)). Use (>@>), (-@>) or (~@>) instead if you are not making any transformations on union and just want to use some members instead.

Examples:

List of multiple members:

foo :: Members '[State Int, Input String] r => Sem (Output [String] : r) () -> Sem r ()

can be written as:

foo :: Output [String] : r @> () -> '[State Int, Input String] >@ r @> ()

One member:

foo :: Member (State Int) r => Sem (Output [String] : r) () -> Sem r ()

can be written as both (with the latter preferred):

foo :: Output [String] : r @> () -> '[State Int] >@ r @> ()

and:

foo :: Output [String] : r @> () -> State Int -@ r @> ()

Exactly one, lifted monad as a member:

foo :: Member (Embed IO) r => Sem (Output [String] : r) () -> Sem r ()

can be written simply as:

foo :: Output [String] : r @> () -> IO ~@ r @> ()

Combined operators

Joined versions of one of (>@), (-@), (~@) and (@>) with implicit, hidden list of effects in union --- suited for actions that only use one Sem in their type.

Examples:

List of members over some Sem:

foo :: Members '[State String, Input Int] r => String -> Int -> Sem r ()

can be written as:

foo :: String -> Int -> '[State String, Input Int] >@> ()

Single member:

foo :: Member (Input Int) r => String -> Int -> Sem r ()

can be written as both (with the latter preferred):

foo :: String -> Int -> '[Input Int] >@> ()

and:

foo :: String -> Int -> Input Int -@> ()

Exactly one, lifted monad as a member:

foo :: Member (Embed IO) r => Sem r ()

can be written simply as:

foo :: IO ~@> ()