7a009f70b6
In interpreter mode, the plugin used to see rows like State (Identity a) ': State a ': r, with an action in State a, and then incorrectly unify that thing with the first thing in the list State (Identity a). As a result, we'd ask for Identity a ~ a, which is infinite, and things would go wrong. Now we instead collect all of the unifications we'd like to do, and only emit the most specific one, as measured by number of type constructors in it. This will now only emit a State (Identity a) ~ State (Identity s), and then unify the state we're looking for, plus the a ~ s that solves the other state action. But the next problem is that we can't determine IndexOf in the row above, because a is a type variable, and so IndexOf is stuck, even though we know IndexOf that_row (State a) ~ 'S 'Z. So the plugin now also solves "stuck" IndexOfs of that form. All of this means we can now happily introduce local effects that have type variables, for effects that are already known to be present in the row. And somehow it just works! Amazing! |
||
---|---|---|
.. | ||
src/Polysemy | ||
test | ||
.gitignore | ||
ChangeLog.md | ||
LICENSE | ||
package.yaml | ||
polysemy-plugin.cabal | ||
README.md | ||
Setup.hs |
polysemy-plugin
Dedication
It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong.
Richard Feynman
Overview
A typechecker plugin that can disambiguate "obvious" uses of effects in
polysemy
.
Example
Consider the following program:
foo :: Member (State Int) r => Sem r ()
foo = put 10
What does this program do? Any human will tell you that it changes the state of
the Int
to 10, which is clearly what's meant.
Unfortunately, polysemy
can't work this out on its own. Its reasoning is
"maybe you wanted to change some other State
effect which is also a Num
,
but you just forgot to add a Member
constraint for it."
This is obviously insane, but it's the way the cookie crumbles.
polysemy-plugin
is a typechecker plugin which will disambiguate the above
program (and others) so the compiler will do what you want.
Usage
Add the following line to your package configuration:
ghc-options: -fplugin=Polysemy.Plugin
Limitations
The polysemy-plugin
will only disambiguate effects if there is exactly one
relevant constraint in scope. For example, it will not disambiguate the
following program:
bar :: Members '[ State Int
, State Double
] r => Sem r ()
bar = put 10
because it is now unclear whether you're attempting to set the Int
or the
Double
. Instead, you can manually write a type application in this case.
bar :: Members '[ State Int
, State Double
] r => Sem r ()
bar = put @Int 10
Acknowledgments
This plugin is copied almost verbatim from simple-effects
.