polysemy-research / polysemy

:gemini: higher-order, no-boilerplate monads
BSD 3-Clause "New" or "Revised" License
1.03k stars 72 forks source link

v2 roadmap #307

Open KingoftheHomeless opened 4 years ago

KingoftheHomeless commented 4 years ago

GHC 8.10 is coming up soon-ish, and we've got plenty of old issues, pull-requests and ideas put on the backburner we should get resolved. Some of these are pretty breaking changes, so I'm aiming at making the next patch v2. Here's a to-do list:

For sures

Maybes

I think it would be good idea to investigate possibility of splitting plugin from the library - currently it's strongly tied to internal machinery, even though the concept could potentially work for any type of constraints and could be useful for other libraries. Plus, building some exact model around how it should work would possibly help us make sure that it's actually sound and safe - typechecker plugins are moving on very thin ice by being able to prove whatever bogus constraint they want.

It seems to me that the idea of [the] plugin is basically "functional dependency that get's dropped if it isn't satisfied" - polysemy-plugin does some other things too I think, but if they're domain-specific, they could just stay where they are. The thing is, I can imagine this plugin being helpful for something like eff or mtl-wthout-fundeps, or even something like implicit arguments or field access - I hope that if we split it, we can possibly attract more contributors into it, simply because they find it useful in their own libraries - And we'll be able to reason about it separately. When it comes to safety, It already blow up a few times in type-incorrect code for me - it's not that bad, because I still get other errors and it seems to be fine once I resolve them, but this is something that will need to be investigated and something that's harder to test being limited just to Member machinery.

If 8.10 is released before we complete everything else, the following point will also become relevant:

Questions about the future

module B where bar :: Member (Tagged "log" (Output String)) r => _

> In some other part of code, I use them together, but forget to point them into corresponding "foo log" and "bar log", having `Tagged "log" _` in scope again, because I find it to be a useful pattern for some terrible reason:
```haskell
do
  ..
  foo _
  bar _
  ..

It happily typechecks - with local model, it would ask "which one is log?", with global it would ask "where is my A.log and B.log?"

The only real solution to this -- if we want to go down that route -- is to implement a GHC plugin for type identifiers. If we do, we can also support neat syntax for these, such as:

foo :: Members { playerCount :: State Int } r => ...

and desugar it into whatever internal representation we choose to have. The choice of internal representation is a thorny one. Preferably, named effects should be opt-in and invisible when they're not used, and the way we represent them should ideally allow for that. We don't want the representation of the effect row to be changed to something too confusing just to support named effects. This might not be possible for solutions that solve the coherence problem. If we can't solve this in a clean way, then this is a big argument for sticking with Tagged, because Tagged is expressed in terms of the already existing representation of the effect row, and is explicitly opt-in.

We won't implement a solution for v2, but we should decide on what direction we should go in.

KingoftheHomeless commented 4 years ago

ctrl+enter why

See this as a WIP of the roadmap.

KingoftheHomeless commented 4 years ago

Ready.