This is really minor but the next commit adds a `runNatS` function that
would require a 5-var forall and that's starting to be really confusing,
making people think why it's there.
Commit 4260466929 added the "r has at
least two elements" constraint to the `Member' t r ('S n)` instance but
`Member t effs` with a general (unknown) effs isn't enough to deduce
that effs is non-empty, so this doesn't typecheck:
f :: Eff (IO ': effs) () -> Eff effs ()
f = undefined
g :: (Member Maybe effs) => Eff effs ()
g = undefined
h :: (Member Maybe effs) => Eff effs ()
h = f g
GHC complains that it could not deduce: `effs ~ (r : rs)` arising from
the use of `g`. It can be worked around by using this instead:
h :: (Member Maybe (e ': es)) => Eff (e ': es) ()
h = f g
but I don't think this is a good user experience, and it's a regression
from 0.2.3.0 that would normally require a major version bump to 0.3 as
it breaks existing code. Therefore a fix should go in quickly and should
get into lts-7 asap.
This commit adds the "effs is non-empty" constraint to `Member t effs`
so the above typechecks again.
Various improvements and fixes.
* Fixed `ifte` and made the `nonDetEffTests` better.
* Fixed `runC` for the `Yield` effect.
* Added a `runM` handler for running an arbitrary monad (if it's the only effect left to handle).
* Added a `modify` function for the State effect.
* Removed the `ProxyState` type wasn't necessary in favor of `Data.Proxy`.
* Made the `Writer` effect work with arbitrary monoids instead of just lists.
See merge request !2
Added Members Constraint
The Members type family (closed) takes two type-level lists, m and r,
as parameters. m contains the effect labels which should be members of
r. The resulting type is a constraint requiring that all elements of m
be members of r.
This simplifies constraints that require multiple members of the same
effect list. For example.
ioState :: (Member IO r, Member (State Int) r) => Eff r ()
becomes
ioState :: Members '[IO, State Int] r => Eff r ()
Furthermore, it allows apps to easily define their typical effect
constraints alongside the typical runtime effect.
type AppEffs = '[State Int, Writer String, IO]
type AppConstraint r = Members AppEffs r
type RunApp = Eff AppEffs
See merge request !1
The Members type family (closed) takes two type-level lists, m and r,
as parameters. m contains the effect labels which should be members of
r. The resulting type is a constraint requiring that all elements of m
be members of r.
This simplifies constraints that require multiple members of the same
effect list. For example.
ioState :: (Member IO r, Member (State Int) r) => Eff r ()
becomes
ioState :: Members '[IO, State Int] r => Eff r ()
Furthermore, it allows apps to easily define their typical effect
constraints alongside the typical runtime effect.
type AppEffs = '[State Int, Writer String, IO]
type AppConstraint r = Members AppEffs r
type RunApp = Eff AppEffs