Safe Haskell | None |
---|---|
Language | Haskell2010 |
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 mString
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
$
IO
() main = program&
runConsoleIO&
runRandomIO
&
runM
-- program :: Members '[Random, ConsoleIO] r => Sem r () program :: '[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
(
constraint in the result - in such cases, use a normal
constraint instead:IO
~@)
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.
Synopsis
- type (@>) = Sem
- type (@-) e = Sem '[e]
- type (@~) m = Sem '[Embed m]
- type (>@) es s = Members es (SemList s) => s
- type (-@) e s = Member e (SemList s) => s
- type (~@) m s = Member (Embed m) (SemList s) => s
- type (>@>) es a = forall r. Members es r => Sem r a
- type (-@>) e a = forall r. Member e r => Sem r a
- type (~@>) m a = forall r. Member (Embed m) r => Sem r a
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
~@>
()