Skip to content

Faster Read and Show for IntSet and Maps? #1265

Open

Description

@Zemyla

The implementations of Show for the various containers are basically showList (toList c). The default showList__ in GHC doesn't use foldr, so it has to create a list and then destroy it. Read uses readList, which has no opportunity to not build an intermediate list.

For Set and Seq, we really can't do better than this, because they use arbitrary Show/Read instances, so we're at their mercy. However, IntSet, IntMap, and Map use the stock instances for Int, (Int, a), and (k, a) respectively, and thus their showList and readList are as the Prelude says.

Show is easier to demonstrate in the limited form of an issue. I'll demonstrate Show IntSet first; the others are similar.

instance Show IntSet where
  showsPrec p s = showParens (p > 10) $ \st -> "fromList [" ++ foldr showOne (']':st) s where
    showOne a sl = shows a $ case sl of
      ']':_ -> sl
      _ -> ',':sl

Read is more complex, but it basically involves parsing fromList and [, then reading the elements directly into a container separated by commas with the same mechanisms as fromList, followed by ]. The question, though, is how many people actually use the Read instances for these.

Activity

  1. meooow25 commented on Oct 21, 2026

    @meooow25
    Contributor

    Yes, I expect these can be made faster, but I don't expect anyone is relying on Show and Read performance in practice.

    But improving the Show instances should be quite harmless, so I am happy to review a PR for it.

    instance Show IntSet where
      showsPrec p s = showParens (p > 10) $ \st -> "fromList [" ++ foldr showOne (']':st) s where
        showOne a sl = shows a $ case sl of
          ']':_ -> sl
          _ -> ',':sl

    This one isn't quite right, it is too strict. For the output to be generated lazily sl must not be inspected.

    For Read, I am less convinced that having more complicated code is worth the trouble.

  2. Zemyla commented on Oct 21, 2026

    @Zemyla
    Author

    This one isn't quite right, it is too strict. For the output to be generated lazily sl must not be inspected.

    shows is lazy in its second argument, so this is only inspecting the head of sl when it would be inspected anyway.

  3. meooow25 commented on Oct 23, 2026

    @meooow25
    Contributor

    Oh, you're right. In the same vein, maybe it would be faster to remove a , at the end, rather than check and add it every time.

    showsPrec2 p s = showParen (p > 10) $
      showString "fromList [" .
      dropComma .
      (\r -> IntSet.foldr (\x -> showChar ',' . shows x) r s) .
      showChar ']'
      where
        dropComma (',':r) = r
        dropComma r = r
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions