Type inference with the Eff monad can be a bit tricky to get right if we want to avoid type annotations. Here are some tips to help you.
When creating effects you can always “require” a stack containing the
right effects with the MemberIn
typeclass:``
You can even use context bounds to make the declaration of
putAndTell
more concise:``
Member
typeclassesThere are 3 different ways to declare that an effect is part of an effect stack with 3 typeclasses:
Typeclass | Alias | Meaning | When to use it |
---|---|---|---|
MemberIn[M, R] |
M |= R |
“M is part of R ” |
to create M effects in R |
MemberInOut[M, R] |
M /= R |
“M is part of R and can be extracted from
it” |
to intercept the effect M (see
Interpreter.scala ) and transform it while staying in the
same stack. For example to handleError for an Error
effect |
Member[M, R] |
M <= R |
“M is part of R , can be extracted from it,
and the resulting stack is m.Out ” |
to interpret the effect in terms of special values or other effects and remove the effect from the stack |
Some function signatures can be repetitive when they always require the same list of effects:
def foo1[R :_foo :_bar :_baz](i: Int): Eff[R, Int]
def foo2[R :_foo :_bar :_baz](i: Int): Eff[R, Int]
def foo3[R :_foo :_bar :_baz](i: Int): Eff[R, Int]
It is possible to “pack” them with the following
_effects
type definition:``
The implicit definition extractMember
in the
Members
object will take care of “unpacking” the member
instances where required. Note that this implicit must not be
in scope when calling the methods requiring the “packed” implicits
otherwise it will trigger a divergent implicit search.