Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Can we de-duplicate Set/Map by leveraging common structure?

Open
#851 10 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
25/100
Issue type
Refactor
Clarity
Needs clarification
Activity status
Stale
Tech stack
haskell
Domain
backend

Research direction

Start with src/Data/Map/Internal.hs and the related Set and Map.Lazy implementations, then compare the shared operations described in pull request 817, including null, size, member, and insert. Investigate whether a shared BinTree representation preserves the stated roles, laziness, and performance. Done means a validated design direction with its trade-offs and an agreed scope for deduplication.

Written by the indexing model from the issue text.

Description

code-quality discussion/rfc

Looking at https://github.com/haskell/containers/pull/817 's

argSet :: Map k a -> Set.Set (Arg k a)
argSet Tip = Set.Tip
argSet (Bin sz kx x l r) = Set.Bin sz (Arg kx x) (argSet l) (argSet r)

it seems the two structures are the same "up to parenthesization"
I wonder if one could exploit this to de-duplicate a good deal of code.

It's not as simple as

newtype Map k a = Map (Set (Arg k a))

since

type role Map nominal representational
type role Set nominal

causes

src/Data/Map/Internal.hs:465:1-38: error:
    • Role mismatch on variable a:
        Annotation says representational but role nominal is required
    • while checking a role annotation for ‘Map’
    |
465 | type role Map nominal representational
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

but maybe we could have the binary tree structure be its own type and then

newtype Set a = Set (BinTree a)
newtype Map k v = Map (BinTree (Arg k v))

allowing a good deal of functions to simply delegate

null :: Set a -> Bool
null (Set t) = BinTree.null t

null :: Map k a -> Bool
null (Map t) = BinTree.null t

There are obvious examples like null, size, member but Set and Map.Lazy may have more similarities - insert seems pretty much the same "up to parenthesization".

It's not obvious to me whether Map can be decomposed like this, since the extra indirection (in this case data Arg a b) interferes with lazyness and performance.

Dominant language
Haskell
Stars
356
Forks
195
Avg merge
2d 17h
Merged PRs (30d)
2

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from haskell/containers

All issues in haskell/containers

Similar issues

More Haskell issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.