Turns out haddocks have been broken forever, but because of haskell/cabal#5977 we never noticed. This PR fixes CI so it breaks (see 6f915b6), and then fixes it by changing the GHC versions under which we're allowed to use loopbreaker. Fixes#160
This function now transforms an Output o into Output [o], which only outputs elements once the specified number of o's have been collected. The only exception is the last element which contains the rest (if any).
This PR changes the plugin so it will notice an insoluble constraint of the form Sem r a ~ Foo, and mark that r takes part in a genuine type error. The plugin will then provide a bogus evidence term for IfStuck (IndexOf r _) _ _, which prevents the AmbiguousSend error message from firing.
runEmbedded lets you interpret a `Lift m` via some `forall x. m x -> IO
x` by pretending all the other polysemy actions are in IO and using its
MonadIO instance.
When emitting messages for ambiguous sends: use `IfStuck` on `r` to
determine if we can compose it. This means `r` is in one of three
states, stuck, cons or nil. We want to wrap it in parentheses iff it's
a cons.
This PR has farmed out the type error machinery out to my new package https://github.com/isovector/type-errors. It's much nicer to work with, and a big red diff!
* Remove explicit loopbreakers, enable plugin
* Use uploaded version of `loopbreaker`
* Fix span of macro
* Disable plugin on GHC <8.6
* Add comment about use of plugin
* Separate unrelated conditions
This shuffles around the error messages so they are only connected to code generated via makeSem. This means that badly-typed interpreters will no longer set off the eager error messages!
This PR adds `runResourceBase` (which is a crap name, but naming things is hard), which interprets `Resource` without the ugly `Sem r ~> IO` parameter. It's a nice solution to #84!
This PR provides a single function withLowerToIO, which runs a desired Sem r effect all the way down to IO, without needing to know the natural transformation beforehand. It does it by running the desired code in a new thread, and shipping all of the unhandled effects back to the main thread. The main thread turns into an event loop for the duration of the withLowerToIO block.
After the clean up in #118, I realized that we no longer need to define hoist in terms of weave. This should save some allocations. After that, I realized it was sort of stupid to keep all of the *Yo functions around. Literally nobody should call them, so I just inlined them into the Union versions.
Red diffs, yeah!
The travis cache appears to be broken (probably due to the nightly stack?), but it just means CI takes like half an hour now. Since I already build on stack, I'm pretty sure it's fine --- also this will give a sanity check against accidentally breaking cabal build plans.
This improves CI times from ~30 minutes down to ~2.
This PR teases apart the reusable pieces of the current TH machinery. Doing so allows us to build other TH abstractions in polysemy --- such as an RPC effect.
This thing was a vestige of the bad old days when you had to write
*instances* of classes things in Polysemy. It was a terrible experience,
and so we don't do that anymore. As a result, the only two instances of
`Effect` were for `Union` and `Yo` --- so I just inlined them.
This PR removes some things in the travis CI that I cargo culted and
didn't understand but am reasonably sure don't do anything except slow
down CI times.
This PR introduces the FCF machinery that will give us more control over writing type-level functions. It defines an IfStuck a b c tyfam that will leave b around if a is stuck, otherwise it will fcf-evaluate c. Everything is polykinded so we can stack these things together to make big logic chains to emit specific variables depending on what exactly is stuck.
This PR adds doctests allowing us to write tests for the custom type errors. Having this stuff reified in the test suite means we can iterate on the implementations and give much better QA.
* Allow bidirectional typechecking in the plugin
The plugin used to choke on this:
```haskell
flipShouldBe 11 . sum . fst . run . runFoldMapOutput id $ do
output [1]
output $ replicate 2 5
```
because it would fail to unify `Output (t Int)` (the polymorphic
`Traversable` variable in `sum`) with `Output [Int]`.
In this case, there are no given constraints, so the plugin is
attempting to solve a `Member (Output (t Int)) '[Output [Int]]`. We
reuse the codepath for unifying wanted/givens, pretending like the
`Output (t Int)` is a given.[^1]
[^1]: Pretending it's a wanted breaks something else that I don't
remember right now. This code is brittle :(
So now we have a "wanted" `Output [Int]`, and a "given" `Output (t
Int)`. In general, this thing isn't OK to solve. Consider a real
example:
```haskell
foo :: Member (Output (t Int)) r => Sem r ()
foo = output [5]
```
This is a type error, because the polymorphism goes the wrong way. We
have no guarantees that `t` is supposed to be `[]`.
But in our original example, this isn't a problem, because our `t` isn't
actually in given position. It's just an artifact of reusing the code!
`mkWanted` now takes a new parameter for whether or not it's OK to allow
the givens to be polymorphic.
Such a thing necessitates a change though. We never want to unify
a polymorphic *effect* in given position. Doing so will break Haskell's
regular type inference that determines what the effect row should be,
based on the order in which the interpreters are run.
* Ensure wanted constraints are emitted only once.
This is a fix for the "solveSimpleWanteds: too many iterations" problem
that people are running into. In these cases, the plugin is being asked
to solve the same `Member` constraint several times, and generating
a new wanted each time. In doing so, GHC thinks that work was done, so
it will ask the plugin to run again next time. This process diverges,
and produces the error.
Fixes#79