Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should we switch to nonempty queues? #65

Open
treeowl opened this issue Dec 1, 2022 · 0 comments
Open

Should we switch to nonempty queues? #65

treeowl opened this issue Dec 1, 2022 · 0 comments

Comments

@treeowl
Copy link
Collaborator

treeowl commented Dec 1, 2022

The Queue type is currently a bit of a mess, in that it doesn't have quite the right amortized bounds. In particular, if someone does something like

q = ((((s <> Empty) <> Empty) <|> Empty) <|> Empty) <|> Empty

and then evaluates viewl q in multiple futures, each of those futures will walk the Emptys to discard them.

We can't give it the right bounds without breaking laziness, a problem which has bitten us rather badly before.

What we can do is replace the catenable queues with lazy catenable non-empty queues. These don't seem to suffer from that problem, so they form a nice clean ADT to built atop. There are a couple pain points:

  1. viewl ends up with a different type, which doesn't match the sequence class we currently use. Not a big deal.
  2. linkAll may get a bit more complicated. I don't know how bad it'll look.
  3. We'll have to define empty :: SeqT a differently. Specifically, we'll need to write
    empty = SeqT (singleton (pure Empty))
    where Empty here is the empty ViewT. This will generally be less efficient to handle than a dedicated Empty constructor in cases where a computation does nothing other than fail. For example, if someone writes m <|> (if x then empty else ...) <|> n then currently we can immediately skip over the Empty when we reach it. With the simplified version, we'll end up with a separate empty for each underlying monad, which contains a (trivial) computation we must "run" to figure out that there's nothing to do. I'm guessing the theoretical cleanliness isn't worth the performance impact, but it depends on the code people want to write.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant