{"id":26264779,"url":"https://github.com/jonathanknowles/monoidmap","last_synced_at":"2025-07-02T20:09:04.921Z","repository":{"id":36976824,"uuid":"485170894","full_name":"jonathanknowles/monoidmap","owner":"jonathanknowles","description":"Monoidal map type with support for semigroup and monoid subclasses.","archived":false,"fork":false,"pushed_at":"2025-06-08T04:44:43.000Z","size":2600,"stargazers_count":19,"open_issues_count":7,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-06-08T05:42:10.745Z","etag":null,"topics":["haskell","map","monoid","monoidmap","total","type"],"latest_commit_sha":null,"homepage":"https://hackage.haskell.org/package/monoidmap","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jonathanknowles.png","metadata":{"files":{"readme":null,"changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-04-25T00:09:15.000Z","updated_at":"2025-06-08T04:44:44.000Z","dependencies_parsed_at":"2023-11-07T01:50:08.448Z","dependency_job_id":"8f6efd76-200b-4cad-99a8-824147b654db","html_url":"https://github.com/jonathanknowles/monoidmap","commit_stats":null,"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"purl":"pkg:github/jonathanknowles/monoidmap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanknowles%2Fmonoidmap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanknowles%2Fmonoidmap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanknowles%2Fmonoidmap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanknowles%2Fmonoidmap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonathanknowles","download_url":"https://codeload.github.com/jonathanknowles/monoidmap/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanknowles%2Fmonoidmap/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263208051,"owners_count":23430676,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["haskell","map","monoid","monoidmap","total","type"],"created_at":"2025-03-14T02:17:59.703Z","updated_at":"2025-07-02T20:09:04.907Z","avatar_url":"https://github.com/jonathanknowles.png","language":"Haskell","readme":"# `monoidmap`\n\u003ca href=\"https://jonathanknowles.github.io/monoidmap/\"\u003e\u003cimg src=\"https://img.shields.io/badge/API-Documentation-227755\" /\u003e\u003c/a\u003e\n\n# Overview\n\nThis library provides a **[`MonoidMap`]** type that:\n\n- models a [total function](#relationship-between-keys-and-values) with [finite support](https://en.wikipedia.org/wiki/Support_(mathematics)) from keys to [monoidal][`Monoid`] values, with a default value of [`mempty`][`Monoid.mempty`].\n- encodes key-value mappings with a [minimal encoding](#encoding) that only\nincludes values _not_ equal to [`mempty`][`Monoid.mempty`].\n- provides a comprehensive set of [monoidal operations](#monoidal-operations) for transforming, combining, and comparing maps.\n- provides a [general basis](#General-basis-for-more-specialised-map-types) for building more specialised monoidal data structures.\n\n# Relationship between keys and values\n\nA map of type \u003ccode\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#t:MonoidMap\"\u003eMonoidMap\u003c/a\u003e k v\u003c/code\u003e associates **every** possible key of type `k` with a value of type `v`:\n\n```hs\nMonoidMap.get :: (Ord k, Monoid v) =\u003e k -\u003e MonoidMap k v -\u003e v\n```\n\nThe [`empty`][`MonoidMap.empty`] map associates every key `k` with a default value of [`mempty`][`Monoid.mempty`]:\n\n```hs\n∀ k. MonoidMap.get k MonoidMap.empty == mempty\n```\n\n## Comparison with standard `Map` type\n\nThe [`MonoidMap`] type differs from the standard [`containers`] [`Map`] type in how it relates keys to values:\n\n|            Type | Models a total function with finite support        |\n|----------------:|:---------------------------------------------------|\n|       `Map k v` | from keys of type `k` to values of type `Maybe v`. |\n| `MonoidMap k v` | from keys of type `k` to values of type `v`.       |\n\nThis difference can be illustrated by comparing the type signatures of operations to query a key for its value, for both types:\n\n```hs\n      Map.lookup ::             k -\u003e       Map k v -\u003e Maybe v\nMonoidMap.get    :: Monoid v =\u003e k -\u003e MonoidMap k v -\u003e       v\n```\n\nWhereas a standard [`Map`] has a default value of [`Nothing`], a [`MonoidMap`] has a default value of [`mempty`][`Monoid.mempty`]:\n\n```hs\n∀ k.       Map.lookup k       Map.empty == Nothing\n∀ k. MonoidMap.get    k MonoidMap.empty == mempty\n```\n\nIn practice, the standard [`Map`] type uses [`Maybe`] to indicate the _presence_ or _absence_ of a value for a particular key. This representation is necessary because the [`Map`] type imposes no constraints on value types.\n\nHowever, _monoidal_ types already have a natural way to represent null or empty values: the [`mempty`][`Monoid.mempty`] constant, which represents the neutral or identity element of a [`Monoid`].\n\nConsequently, using a standard [`Map`] with a _monoidal_ value type gives rise to _two_ distinct representations for null or empty values:\n\n| `Map.lookup k m` | Interpretation                                              |\n|:-----------------|:------------------------------------------------------------|\n| `Nothing`        | Map `m` has _no_ entry for key `k`.                         |\n| `Just mempty`    | Map `m` has an entry for key `k`, but the value is _empty_. |\n\nIn contrast, the [`MonoidMap`] type provides a single, _canonical_ representation for null or empty values, according to the following conceptual mapping:\n\n| `Map.lookup k m`        | ⟼ | `MonoidMap.get k m`     |\n|:------------------------|---|:------------------------|\n| `Nothing`               | ⟼ | `mempty`                |\n| `Just v \\| v == mempty` | ⟼ | `mempty`                |\n| `Just v \\| v /= mempty` | ⟼ | `v`                     |\n\n## Advantages of using a canonical representation\n\nA canonical representation for [`mempty`][`Monoid.mempty`] values can make it easier to correctly implement operations that compare or combine pairs of maps.\n\nWhen comparing or combining maps of the standard [`containers`] [`Map`] type, there are **two** cases to consider for each key `k` in each map:\n\n- [`Map`] `m` associates `k` with `Nothing`.\n- [`Map`] `m` associates `k` with `Just v`.\n\nWith a _pair_ of maps, there are **four** possible cases to consider for each key.\n\nFor maps with monoidal values, and in contexts that assume or require a default value of [`mempty`][`Monoid.mempty`], there are now **three** cases to consider for each map:\n\n- [`Map`] `m` associates `k` with `Nothing`.\n- [`Map`] `m` associates `k` with `Just v` where `v == mempty`.\n- [`Map`] `m` associates `k` with `Just v` where `v /= mempty`.\n\nWith a _pair_ of maps, there are now **nine** possible cases to consider for each key.\n\nMishandling cases such as these can give rise to subtle bugs that manifest in unexpected places. For maps with more complex value types (such as maps that nest other maps), the number of cases requiring consideration can easily multiply further, making it even easier to introduce bugs.\n\nSince all [`MonoidMap`] operations provide a canonical representation for [`mempty`][`Monoid.mempty`] values, it's possible to write functions that compare or combine maps without having to consider [`Nothing`] and \u003ccode\u003e\u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Maybe.html#v:Just\"\u003eJust\u003c/a\u003e \u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Monoid.html#v:mempty\"\u003emempty\u003c/a\u003e\u003c/code\u003e as separate cases.\n\n# Encoding\n\nA [`MonoidMap`] only encodes mappings from keys to values that are **_not_** equal to [`mempty`][`Monoid.mempty`].\n\nThe total function $T$ modelled by a [`MonoidMap`] is encoded as a **support map** $S$, where $S$ is the finite subset of key-value mappings in $T$ for which values are **_not_** equal to [`mempty`][`Monoid.mempty`] (denoted by $\\varnothing$):\n\n\u003e $S = \\\\{ \\(k, v\\) \\in T \\ \\|\\ v \\ne \\varnothing \\\\} $\n\n## Automatic minimisation\n\nAll [`MonoidMap`] operations perform **automatic minimisation** of the support map, so that [`mempty`][`Monoid.mempty`] values do not appear in:\n- any encoding of a [`MonoidMap`];\n- any traversal of a [`MonoidMap`].\n\n## Constraints on values\n\n[`MonoidMap`] operations require the monoidal value type to be an instance of [`MonoidNull`].\n\nInstances of [`MonoidNull`] must provide a [`null`][`MonoidNull.null`] indicator function that satisfies the following law:\n\n```hs\nnull v == (v == mempty)\n```\n\n[`MonoidMap`] operations use the [`null`][`MonoidNull.null`] indicator function to detect and exclude [`mempty`][`Monoid.mempty`] values from the support map.\n\nNote that it is _not_ generally necessary for the value type to be an instance of [`Eq`].\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eJustification\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\n\u003e The set of monoidal types that admit a [`MonoidNull`] instance is strictly larger than the set of monoidal types that admit an [`Eq`] instance.\n\u003e\n\u003e For any type `v` that is an instance of both [`Eq`] and [`Monoid`], it is _always_ possible to define a [`MonoidNull`] instance:\n\u003e\n\u003e ```hs\n\u003e instance MonoidNull v where\n\u003e     null = (== mempty)\n\u003e ```\n\u003e\n\u003e However, there are monoidal types for which it is possible to define a [`MonoidNull`] instance, but not practical (or possible) to define a lawful [`Eq`] instance.\n\u003e\n\u003e For example, consider the following type:\n\u003e ```hs\n\u003e Maybe (String -\u003e Sum Natural)\n\u003e ```\n\u003e\n\u003e Requiring a [`MonoidNull`] constraint instead of an [`Eq`] constraint allows [`MonoidMap`] to be usable with a greater range of monoidal value types.\n\n\u003c/details\u003e\n\n## Examples of automatic minimisation\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eUpdating a map with a value that \u003cem\u003emay\u003c/em\u003e be \u003ccode\u003emempty\u003c/code\u003e\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\n\u003e Consider the following operation, which constructs a map of type `MonoidMap Int String`:\n\u003e\n\u003e ```hs\n\u003e \u003e\u003e\u003e m0 = fromList [(1, \"hello\"), (2, \"brave\"), (3, \"new\"), (4, \"world\")]\n\u003e \u003e\u003e\u003e m0\n\u003e fromList [(1, \"hello\"), (2, \"brave\"), (3, \"new\"), (4, \"world\")]\n\u003e ```\n\u003e\n\u003e The [`Monoid`] instance for [`String`] defines [`mempty`][`Monoid.mempty`] to be the empty [`String`] `\"\"`.\n\u003e\n\u003e If we update the map to associate key `3` with value `\"\"`, that association will no longer appear when encoding the map:\n\u003e\n\u003e ```hs\n\u003e \u003e\u003e\u003e m1 = MonoidMap.set 3 \"\" m0\n\u003e \u003e\u003e\u003e m1\n\u003e fromList [(1, \"hello\"), (2, \"brave\"), (4, \"world\")]\n\u003e ```\n\u003e\n\u003e However, we can still read the updated value for key `3`:\n\u003e ```hs\n\u003e \u003e\u003e\u003e MonoidMap.get 3 m1\n\u003e \"\"\n\u003e ```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eConstructing a map from a list that \u003cem\u003emay\u003c/em\u003e include \u003ccode\u003emempty\u003c/code\u003e values\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\n\u003e Consider the following operation, which constructs a map of type `MonoidMap Char (Sum Natural)`:\n\u003e\n\u003e ```hs\n\u003e \u003e\u003e\u003e m = fromList [('a', Sum 0), ('b', Sum 1), ('c', Sum 2), ('d', Sum 3)]\n\u003e ```\n\u003e The [`Monoid`] instance for \u003ccode\u003e\u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Monoid.html#v:Sum\"\u003eSum\u003c/a\u003e \u003ca href=\"https://hackage.haskell.org/package/base/docs/Numeric-Natural.html#t:Natural\"\u003eNatural\u003c/a\u003e\u003c/code\u003e defines [`mempty`][`Monoid.mempty`] to be `Sum 0`.\n\u003e\n\u003e The original list contained a mapping from key `'a'` to value `Sum 0`, but that association will not appear when encoding the map:\n\u003e\n\u003e ```hs\n\u003e \u003e\u003e\u003e m\n\u003e fromList [('b', Sum 1), ('c', Sum 2), ('d', Sum 3)]\n\u003e ```\n\u003e\n\u003e Nevertheless, we can still read the value for key `'a'`:\n\u003e ```hs\n\u003e \u003e\u003e\u003e MonoidMap.get 'a' m\n\u003e Sum 0\n\u003e ```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eCombining maps with operations that \u003cem\u003emay\u003c/em\u003e produce \u003ccode\u003emempty\u003c/code\u003e values\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\n\u003e Consider the following operations, which construct two maps of type `MonoidMap Char (Sum Natural)`:\n\u003e\n\u003e ```hs\n\u003e \u003e\u003e\u003e m1 = fromList [('a', Sum 1), ('b', Sum   1 )]\n\u003e \u003e\u003e\u003e m2 = fromList [('a', Sum 1), ('b', Sum (-1))]\n\u003e ```\n\u003e\n\u003e The [`Semigroup`] instance for \u003ccode\u003e\u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Monoid.html#v:Sum\"\u003eSum\u003c/a\u003e \u003ca href=\"https://hackage.haskell.org/package/base/docs/Numeric-Natural.html#t:Natural\"\u003eNatural\u003c/a\u003e\u003c/code\u003e defines [`\u003c\u003e`] as equivalent to ordinary addition.\n\u003e\n\u003e If we add both maps together with [`\u003c\u003e`], then each key in the resulting map will be associated with the result of applying [`\u003c\u003e`] to each matching pair of values in the original maps. However, adding together the values for key `'b'` with [`\u003c\u003e`] produces `Sum 0`, so this value will not appear in the encoding:\n\u003e\n\u003e ```hs\n\u003e \u003e\u003e\u003e m1 \u003c\u003e m2\n\u003e fromList [('a', Sum 2)]\n\u003e ```\n\u003e\n\u003e Nevertheless, we can still read the value for key `'b'`:\n\u003e ```hs\n\u003e \u003e\u003e\u003e MonoidMap.get 'b' (m1 \u003c\u003e m2)\n\u003e Sum 0\n\u003e ```\n\n\u003c/details\u003e\n\n## Advantages of automatic minimisation\n\n### Consistency\n\nAutomatic exclusion of [`mempty`][`Monoid.mempty`] values can help to ensure consistency when encoding to or decoding from other formats such as JSON, CBOR, or YAML.\n\nFor example, you may wish to ensure that:\n\n- When _encoding_ a map, no [`mempty`][`Monoid.mempty`] values appear in the encoded result.\n- When _decoding_ a map, no [`mempty`][`Monoid.mempty`] values appear in the decoded result.\n\n### Performance\n\nAutomatic exclusion of [`mempty`][`Monoid.mempty`] values makes it possible to perform certain operations in _constant time_, rather than in linear time, as it is never necessary to traverse the entire map in order to determine which values may or may not be [`mempty`][`Monoid.mempty`]:\n\n\u003ctable\u003e\n\u003cthead\u003e\n  \u003ctr valign=\"top\" align=\"left\"\u003e\n    \u003cth\u003eOperation\u003c/th\u003e\n    \u003cth\u003eWith\u003cbr\u003eAutomatic\u003cbr\u003eMinimisation\u003c/th\u003e\n    \u003cth\u003eWithout\u003cbr\u003eAutomatic\u003cbr\u003eMinimisation\u003c/th\u003e\n  \u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:null\" rel=\"nofollow\"\u003e\u003ccode\u003enull\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e$O(1)$\u003c/td\u003e\n    \u003ctd\u003e$O(n)$\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:nonNull\" rel=\"nofollow\"\u003e\u003ccode\u003enonNull\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e$O(1)$\u003c/td\u003e\n    \u003ctd\u003e$O(n)$\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:nonNullCount\" rel=\"nofollow\"\u003e\u003ccode\u003enonNullCount\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e$O(1)$\u003c/td\u003e\n    \u003ctd\u003e$O(n)$\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:toMap\" rel=\"nofollow\"\u003e\u003ccode\u003etoMap\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e$O(1)$\u003c/td\u003e\n    \u003ctd\u003e$O(n)$\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n### Memory usage\n\nAutomatic minimisation makes it easier to reason about the memory usage of a [`MonoidMap`], as memory is not required to encode mappings from keys to empty values.\n\nThis is a useful property for large, long-lived map structures that are subject to multiple updates over their lifetimes, where it's important to not retain large numbers of mappings from keys to empty values.\n\n### Simplicity\n\nSome total map data types only perform minimisation when _explicitly demanded to_.\n\nFor example, the [`TMap`] data type provides a [`trim`][`TMap.trim`] operation that traverses the map and removes any values that are equal to the _default_ value. This approach has some advantages, such the ability to provide a lawful [`Functor`] instance.\n\nHowever, this approach also has some disadvantages:\n- It might not be obvious _when_ it's necessary to call [`trim`][`TMap.trim`]. For example, consider the following operation: `m1 \u003c\u003e m2`. Could this operation produce a map where some keys map to default values? (Answer: it depends on the choice of default value and the underlying value type.)\n- Calling [`trim`][`TMap.trim`] when it _isn't_ necessary might adversely affect performance, since [`trim`][`TMap.trim`] must traverse the entire data structure.\n- Not calling [`trim`][`TMap.trim`] when it _is_ necessary might affect correctness. The compiler will not help here, as trimmed and untrimmed maps share the same type.\n- Even if [`trim`][`TMap.trim`] is a semantic no-op, default values can _still_ be made visible by operations that encode maps to other types.\n\nSince all [`MonoidMap`] operations perform automatic minimisation when appropriate, it's not necessary for users to reason about when or whether it's necessary to \"trim\" the map.\n\nFurthermore, for nested maps such as \u003ccode\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#t:MonoidMap\"\u003eMonoidMap\u003c/a\u003e k1 (\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#t:MonoidMap\"\u003eMonoidMap\u003c/a\u003e k2 v)\u003c/code\u003e, automatic minimisation of inner maps enables seamless automatic minimisation of outer maps. See the [`NestedMonoidMap`] type for an example of this.\n\n## Limitations of automatic minimisation\n\nThe [`MonoidMap`] type has no [`Functor`] instance, as the requirement to exclude [`mempty`][`Monoid.mempty`] values means that the [`map`][`MonoidMap.map`] operation must remove [`mempty`][`Monoid.mempty`] values from its result. Therefore, [`map`][`MonoidMap.map`] does _not_ unconditionally satisfy the functor composition law:\n\n```hs\nmap (f . g) == map f . map g\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample violation\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nConsider the following [`MonoidMap`] `m`:\n```hs\nm :: MonoidMap String String\nm = singleton \"k\" \"v\"\n```\n\nAnd the following functions `f` and `g`:\n```hs\nf :: a -\u003e String\nf = const \"z\"\n\ng :: Monoid a =\u003e b -\u003e a\ng = const mempty\n```\n\nBy substituting the above definitions into the left-hand side of the functor composition law, we obtain:\n```hs\nmap (f . g) m = map (const \"z\" . const mempty) (singleton \"k\" \"v\")\n              = map (const \"z\"               ) (singleton \"k\" \"v\")\n              =                                (singleton \"k\" \"z\")\n```\n\nBy substituting the above definitions into the right-hand side of the functor composition law, we obtain:\n```hs\nmap f (map g m) = map (const \"z\") (map (const mempty) (singleton \"k\" \"v\"))\n                = map (const \"z\") mempty\n                =                 mempty\n```\n\nThis leads to the following inequality between the left-hand side and right-hand side:\n```hs\nsingleton \"k\" \"z\" /= mempty\n```\nTherefore, for this example, the functor composition law is not satisfied.\n\n\u003c/details\u003e\n\nHowever, if applying function `f` to [`mempty`][`Monoid.mempty`] produces [`mempty`][`Monoid.mempty`], the functor composition law is satisfied:\n\n```hs\n(f mempty == mempty) ==\u003e (∀ g. map (f . g) == map f . map g)\n```\n\n# Monoidal operations\n\nThe [`MonoidMap`] type provides a comprehensive set of monoidal operations for transforming, combining, and comparing maps.\n\nInstances for several _subclasses_ of [`Semigroup`] and [`Monoid`] are provided, including classes from the following libraries:\n\n- [`monoid-subclasses`]\n- [`groups`]\n\nAt the root of this hierarchy of subclasses is the [`Semigroup`] class, whose instance for [`MonoidMap`] is defined in terms of the _underlying value type_, so that applying [`\u003c\u003e`] to a _pair of maps_ is equivalent to applying [`\u003c\u003e`] to all _pairs of values_ for matching keys:\n\n```hs\n∀ k. MonoidMap.get k (m1 \u003c\u003e m2) == MonoidMap.get k m1 \u003c\u003e get k m2\n```\n\nIn general, operations for subclasses of [`Semigroup`] and [`Monoid`] are defined _analogously_ to the [`Semigroup`] instance, so that:\n\n- _unary_ operations on _individual maps_ are defined in terms of their distributive application to all values.\n- _binary_ operations on _pairs of maps_ are defined in terms of their distributive application to all _pairs of values_ for matching keys.\n\nUnary monoidal operations typically satisfy a property similar to:\n\n```hs\n∀ k. MonoidMap.get k (f m) == f (MonoidMap.get k m)\n```\n\nBinary monoidal operations typically satisfy a property similar to:\n\n```hs\n∀ k. MonoidMap.get k (f m1 m2) == f (MonoidMap.get k m1) (MonoidMap.get k m2)\n```\n\nDefining monoidal operations in this way makes it possible to transform, combine, and compare maps in ways that are consistent with the algebraic properties of the underlying monoidal value type.\n\n## Examples of monoidal operations and their properties\n\n\u003ctable\u003e\n\u003cthead\u003e\n  \u003ctr valign=\"top\" align=\"left\"\u003e\n    \u003cth\u003e\u003ccode\u003eMonoidMap\u003c/code\u003e\u003cbr\u003eoperation\u003c/th\u003e\n    \u003cth\u003eRequired\u003cbr\u003eclass\u003cbr\u003econstraint\u003c/th\u003e\n    \u003cth\u003eEquivalent\u003cbr\u003eclass\u003cbr\u003emethod\u003c/th\u003e\n    \u003cth\u003eDistributive\u003cbr\u003erelationship\u003c/th\u003e\n  \u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:append\"\u003e\u003ccode\u003eappend\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Semigroup.html#t:Semigroup\"\u003e\u003ccode\u003eSemigroup\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Semigroup.html#v:-60--62-\"\u003e\u003ccode\u003e(\u0026lt;\u0026gt;)\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e∀ k. \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k (m1  \u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Semigroup.html#v:-60--62-\"\u003e\u003c\u003e\u003c/a\u003e   m2) ≡ \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k m1  \u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Semigroup.html#v:-60--62-\"\u003e\u003c\u003e\u003c/a\u003e   \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k m2\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:minus\"\u003e\u003ccode\u003eminus\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://hackage.haskell.org/package/groups/docs/Data-Group.html#t:Group\"\u003e\u003ccode\u003eGroup\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://hackage.haskell.org/package/groups/docs/Data-Group.html#v:-126--126-\"\u003e\u003ccode\u003e(~~)\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e∀ k. \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k (m1  \u003ca href=\"https://hackage.haskell.org/package/groups/docs/Data-Group.html#v:-126--126-\"\u003e~~\u003c/a\u003e   m2) ≡ \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k m1  \u003ca href=\"https://hackage.haskell.org/package/groups/docs/Data-Group.html#v:-126--126-\"\u003e~~\u003c/a\u003e   \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k m2\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:monus\"\u003e\u003ccode\u003emonus\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-Monus.html#t:Monus\"\u003e\u003ccode\u003eMonus\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-Monus.html#v:-60--92--62-\"\u003e\u003ccode\u003e(\u0026lt;\\\u0026gt;)\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e∀ k. \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k (m1  \u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-Monus.html#v:-60--92--62-\"\u003e\u003c\\\u003e\u003c/a\u003e  m2) ≡ \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k m1  \u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-Monus.html#v:-60--92--62-\"\u003e\u003c\\\u003e\u003c/a\u003e  \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k m2\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:intersection\"\u003e\u003ccode\u003eintersection\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-GCD.html#t:GCDMonoid\"\u003e\u003ccode\u003eGCDMonoid\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-GCD.html#v:gcd\"\u003e\u003ccode\u003egcd\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e∀ k. \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k (m1 `\u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-GCD.html#v:gcd\"\u003egcd\u003c/a\u003e` m2) ≡ \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k m1 `\u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-GCD.html#v:gcd\"\u003egcd\u003c/a\u003e` \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k m2\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:union\"\u003e\u003ccode\u003eunion\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-LCM.html#t:LCMMonoid\"\u003e\u003ccode\u003eLCMMonoid\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-LCM.html#v:lcm\"\u003e\u003ccode\u003elcm\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e∀ k. \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k (m1 `\u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-LCM.html#v:lcm\"\u003elcm\u003c/a\u003e` m2) ≡ \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k m1 `\u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-LCM.html#v:lcm\"\u003elcm\u003c/a\u003e` \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:get\"\u003eget\u003c/a\u003e k m2\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n## Examples of monoidal operations applied to values\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample: \u003ccode\u003eMonoidMap k (Set Integer)\u003c/code\u003e\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nFor maps with [`Set`]-based values, [`MonoidMap.union`] and [`MonoidMap.intersection`] compute the [`Set.union`] and [`Set.intersection`] of each pair of matching values, respectively.\n\nConsider the following maps of type `MonoidMap Char (Set Integer)`:\n\n```hs\n\u003e\u003e\u003e m1 = fromList [('a', Set.fromList [0, 1]), ('b', Set.fromList [3, 4])]\n\u003e\u003e\u003e m2 = fromList [('a', Set.fromList [0, 2]), ('b', Set.fromList [3, 5])]\n```\n\nThe [`MonoidMap.union`] of maps `m1` and `m2` is a map that associates every key `k` with the [`Set.union`] of the corresponding sets for `k` in `m1` and `m2`:\n\n```hs\n\u003e\u003e\u003e m1 `union` m2\nfromList [('a', Set.fromList [0,1,2]), ('b', Set.fromList [3,4,5])]\n```\n\nThe [`MonoidMap.intersection`] of maps `m1` and `m2` is a map that associates every key `k` with the [`Set.intersection`] of the corresponding sets for `k` in `m1` and `m2`:\n\n```hs\n\u003e\u003e\u003e m1 `intersection` m2\nfromList [('a', Set.fromList [0]), ('b', Set.fromList [3])]\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample: \u003ccode\u003eMonoidMap k (Sum Integer)\u003c/code\u003e\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nConsider the following maps of type `MonoidMap Char (Sum Integer)`:\n\n```hs\n\u003e\u003e\u003e m1 = fromList [('a', Sum 10), ('b', Sum 20), ('c, Sum 40)]\n\u003e\u003e\u003e m2 = fromList [('a', Sum 40), ('b', Sum 20), ('c, Sum 10)]\n```\n\nThe [`MonoidMap.invert`] operation produces a new map where every key is associated with the negation of its value in the original map:\n\n```hs\n\u003e\u003e\u003e invert m1\nfromList [('a', Sum (-10)), ('b', Sum (-20)), ('c, Sum (-40))]\n\n\u003e\u003e\u003e invert m2\nfromList [('a', Sum (-40)), ('b', Sum (-20)), ('c, Sum (-10))]\n```\n\nThe [`MonoidMap.minus`] operation, when applied to maps `m1` and `m2`, produces a new map where every key `k` is associated with the value of `k` in `m1` minus the value of `k` in `m2`:\n\n```hs\n\u003e\u003e\u003e m1 `minus` m2\nfromList [('a', Sum (-30)), ('c', Sum 30)]\n\n\u003e\u003e\u003e m2 `minus` m1\nfromList [('a', Sum 30), ('c', Sum (-30))]\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample: \u003ccode\u003eMonoidMap k (Sum Natural)\u003c/code\u003e\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nFor maps with \u003ccode\u003e\u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Monoid.html#v:Sum\"\u003eSum\u003c/a\u003e \u003ca href=\"https://hackage.haskell.org/package/base/docs/Numeric-Natural.html#t:Natural\"\u003eNatural\u003c/a\u003e\u003c/code\u003e values, [`MonoidMap.union`] and [`MonoidMap.intersection`] compute the _maximum_ and _minimum_ of each pair of matching values, respectively:\n\n```hs\n\u003e\u003e\u003e m1 = fromList [('a', Sum 10), ('b', Sum 20)]\n\u003e\u003e\u003e m2 = fromList [('a', Sum 20), ('b', Sum 10)]\n\n\u003e\u003e\u003e m1 `union` m2\nfromList [('a', Sum 20), ('b', Sum 20)]\n\n\u003e\u003e\u003e m1 `intersection` m2\nfromList [('a', Sum 10), ('b', Sum 10)]\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample: \u003ccode\u003eMonoidMap k (Product Natural)\u003c/code\u003e\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nFor maps with \u003ccode\u003e\u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Monoid.html#v:Product\"\u003eProduct\u003c/a\u003e \u003ca href=\"https://hackage.haskell.org/package/base/docs/Numeric-Natural.html#t:Natural\"\u003eNatural\u003c/a\u003e\u003c/code\u003e values, [`MonoidMap.union`] and [`MonoidMap.intersection`] compute the _lowest common multiple_ (LCM) and _greatest common divisor_ (GCD) of each pair of matching values, respectively:\n\n```hs\n\u003e\u003e\u003e m1 = fromList [('a', Product  6), ('b', Product 15), ('c', Product 35)]\n\u003e\u003e\u003e m2 = fromList [('a', Product 15), ('b', Product 35), ('c', Product 77)]\n\n\u003e\u003e\u003e m1 `union` m2\nfromList [('a', Product 30), ('b', Product 105), ('c', Product 385)]\n\n\u003e\u003e\u003e m1 `intersection` m2\nfromList [('a', Product 3), ('b', Product 5), ('c', Product 7)]\n```\n\u003c/details\u003e\n\n# General basis for more specialised map types\n\nThe [`MonoidMap`] type can be used as a general basis for building other more specialised map types.\n\nIf you have a [`Map`]-based data type with an invariant that values **must not** be [`mempty`][`Monoid.mempty`], then by expressing this type in terms of [`MonoidMap`], [`MonoidMap`] will handle the invariant for you:\n\n```patch\n- newtype SomeMap k v = SomeMap (      Map k (SomeMonoidalContainer v))\n+ newtype SomeMap k v = SomeMap (MonoidMap k (SomeMonoidalContainer v))\n```\n\nIf you're already using a specialised non-empty container type to enforce the invariant that values must not be empty, then [`MonoidMap`] makes it possible to _replace_ the use of the specialised non-empty container type with its ordinary equivalent:\n\nExample transformations:\n```patch\n  -- Non-empty lists:\n- newtype ListMap k v = ListMap (      Map k (NonEmpty v))\n+ newtype ListMap k v = ListMap (MonoidMap k          [v])\n\n  -- Non-empty sets:\n- newtype SetMap k v = SetMap (      Map k (NonEmptySet v))\n+ newtype SetMap k v = SetMap (MonoidMap k         (Set v))\n\n  -- Non-empty sequences:\n- newtype SeqMap k v = SeqMap (      Map k (NonEmptySeq v))\n+ newtype SeqMap k v = SeqMap (MonoidMap k         (Seq v))\n```\n\nUsing [`MonoidMap`] can simplify the implementation of such types, as special handling code for empty values can often be greatly simplified or even eliminated.\n\n## Real-world examples from the Haskell ecosystem\n\n### Example: `SignedMultiSet` (a signed multiset type)\n\n\u003e The [`signed-multiset`] library provides the [`SignedMultiSet`] type, which is internally defined as a [`Map`] from elements to signed integer occurrence counts:\n\u003e\n\u003e ```hs\n\u003e newtype SignedMultiset a = SMS {unSMS :: Map a Int}\n\u003e ```\n\u003e\n\u003e All [`SignedMultiSet`] operations maintain an invariant that the internal [`Map`] **must not** contain any mappings to `0` (zero). This requires [`SignedMultiSet`] functions to detect and eliminate values of `0`.\n\u003e\n\u003e For example, the [`insertMany`][`SignedMultiSet.insertMany`] operation:\n\u003e\n\u003e ```hs\n\u003e insertMany :: Ord a =\u003e a -\u003e Int -\u003e SignedMultiset a -\u003e SignedMultiset a\n\u003e insertMany x n = SMS . Map.alter f x . unSMS\n\u003e   where\n\u003e     f Nothing  = Just n\n\u003e     f (Just m) = let k = m + n in if k == 0 then Nothing else Just k\n\u003e ```\n\u003e\n\u003e Let's redefine [`SignedMultiSet`] in terms of [`MonoidMap`]:\n\u003e\n\u003e ```diff\n\u003e - newtype SignedMultiset a = SMS {unSMS ::       Map a      Int }\n\u003e + newtype SignedMultiset a = SMS {unSMS :: MonoidMap a (Sum Int)}\n\u003e ```\n\u003e\n\u003e Here we've used the [`Sum`] wrapper type, whose [`Monoid`] instance defines [`mempty`][`Monoid.mempty`] as `Sum 0`, and [`\u003c\u003e`] as ordinary addition.\n\u003e\n\u003e Now we can redefine [`insertMany`][`SignedMultiSet.insertMany`] (and similar operations) in a simpler way:\n\u003e\n\u003e ```patch\n\u003e   insertMany :: Ord a =\u003e a -\u003e Int -\u003e SignedMultiset a -\u003e SignedMultiset a\n\u003e + insertMany x n = SMS . MonoidMap.adjust (+ Sum n) x . unSMS\n\u003e - insertMany x n = SMS . Map.alter f x . unSMS\n\u003e -   where\n\u003e -     f Nothing  = Just n\n\u003e -     f (Just m) = let k = m + n in if k == 0 then Nothing else Just k\n\u003e ```\n\u003e\n\u003e Since the [`MonoidMap.adjust`] operation performs automatic minimisation, values of `Sum 0` are automatically excluded from the internal data structure, and there is no need to handle them differently from non-zero values.\n\n### Example: `SetMultiMap` (a set-based multimap type)\n\n\u003e The [`multi-containers`] library provides the [`SetMultiMap`] type, which is internally defined as a [`Map`] from keys to (possibly-empty) sets of values, together with a `Size` parameter that records the total number of elements in the map (counting duplicates):\n\u003e\n\u003e ```hs\n\u003e newtype SetMultimap k a = SetMultimap (Map k (Set a), Size)\n\u003e type Size = Int\n\u003e ```\n\u003e\n\u003e All [`SetMultiMap`] operations maintain an invariant that the internal [`Map`] **must not** contain any mappings to empty sets. This requires [`SetMultiMap`] functions to detect and eliminate values of [`Set.empty`] (indicated by the [`Set.null`] function).\n\u003e\n\u003e For example, the [`alterWithKey`][`SetMultiMap.alterWithKey`] operation detects if the updated set is empty, and if so, performs a deletion instead of an insertion:\n\u003e\n\u003e ```hs\n\u003e alterWithKey :: Ord k =\u003e (k -\u003e Set a -\u003e Set a) -\u003e k -\u003e SetMultimap k a -\u003e SetMultimap k a\n\u003e alterWithKey f k mm@(SetMultimap (m, _))\n\u003e     | Set.null as = fromMap (Map.delete k    m)\n\u003e     | otherwise   = fromMap (Map.insert k as m)\n\u003e   where\n\u003e     as = f k (mm ! k)\n\u003e\n\u003e fromMap :: Map k (Set a) -\u003e SetMultimap k a\n\u003e fromMap m = SetMultimap (m', sum (fmap Set.size m'))\n\u003e   where\n\u003e     m' = Map.filter (not . Set.null) m\n\u003e ```\n\u003e\n\u003e Let's redefine [`SetMultiMap`] in terms of [`MonoidMap`]:\n\u003e\n\u003e ```patch\n\u003e - newtype SetMultimap k a = SetMultimap (      Map k (Set a), Size)\n\u003e + newtype SetMultimap k a = SetMultimap (MonoidMap k (Set a), Size)\n\u003e ```\n\u003e\n\u003e Now we can provide a simpler definition for [`alterWithKey`][`SetMultiMap.alterWithKey`] (and other operations):\n\u003e\n\u003e ```hs\n\u003e alterWithKey :: Ord k =\u003e (k -\u003e Set a -\u003e Set a) -\u003e k -\u003e SetMultimap k a -\u003e SetMultimap k a\n\u003e alterWithKey f k (SetMultimap (m, size)) = SetMultiMap\n\u003e     (MonoidMap.set k new m, size - Set.size old + Set.size new)\n\u003e   where\n\u003e     old = MonoidMap.get k m\n\u003e     new = f k old\n\u003e ```\n\u003e\n\u003e Since the [`MonoidMap.set`] operation performs automatic minimisation, empty sets are automatically excluded from the internal data structure, and there is no need to handle them any differently from non-empty sets.\n\n### Example: `MultiMap` (a list-based multimap type)\n\n\u003e The [`multi-containers`] library provides the [`MultiMap`] type, which is internally defined as a [`Map`] from keys to non-empty lists of values, together with a `Size` parameter that records the total number of elements in the map (counting duplicates):\n\u003e\n\u003e ```hs\n\u003e newtype Multimap k a = Multimap (Map k (NonEmpty a), Size)\n\u003e type Size = Int\n\u003e ```\n\u003e\n\u003e All [`MultiMap`] operations maintain the invariant that the internal [`Map`] **must not** contain any mappings to empty lists. This invariant is handled rather nicely by the use of the [`NonEmpty`] list type, which disallows empty lists _by construction_. As a result, it's arguably more difficult to make a mistake in the implementation than it would be if [`MultiMap`] were defined in terms of ordinary lists.\n\u003e\n\u003e However, certain operations still need to differentiate between the empty and non-empty case, and it's still necessary to handle each case specially.\n\u003e\n\u003e For example, the [`alterWithKey`][`MultiMap.alterWithKey`] operation detects if the updated list is empty, and if so, performs a deletion instead of an insertion:\n\u003e\n\u003e ```hs\n\u003e alterWithKey :: Ord k =\u003e (k -\u003e [a] -\u003e [a]) -\u003e k -\u003e Multimap k a -\u003e Multimap k a\n\u003e alterWithKey f k mm@(Multimap (m, _)) = case nonEmpty (f k (mm ! k)) of\n\u003e     Just as' -\u003e fromMap (Map.insert k as' m)\n\u003e     Nothing  -\u003e fromMap (Map.delete k     m)\n\u003e\n\u003e fromMap :: Map k (NonEmpty a) -\u003e Multimap k a\n\u003e fromMap m = Multimap (m, sum (fmap length m))\n\u003e ```\n\u003e\n\u003e Let's redefine [`MultiMap`] in terms of [`MonoidMap`] and ordinary lists:\n\u003e\n\u003e ```patch\n\u003e - newtype Multimap k a = Multimap (      Map k (NonEmpty a), Size)\n\u003e + newtype Multimap k a = Multimap (MonoidMap k          [a], Size)\n\u003e ```\n\u003e\n\u003e Now we can provide a simpler definition for [`alterWithKey`][`MultiMap.alterWithKey`] (and other operations):\n\u003e ```hs\n\u003e alterWithKey :: Ord k =\u003e (k -\u003e [a] -\u003e [a]) -\u003e k -\u003e Multimap k a -\u003e Multimap k a\n\u003e alterWithKey f k (Multimap (m, size)) = MultiMap\n\u003e     (MonoidMap.set k new m, size - List.length old + List.length new)\n\u003e   where\n\u003e     old = MonoidMap.get k m\n\u003e     new = f k old\n\u003e ```\n\u003e\n\u003e Since the [`MonoidMap.set`] operation performs automatic minimisation:\n\u003e - empty lists are automatically excluded from the internal data structure.\n\u003e - there is no need to use a specialised [`NonEmpty`] type.\n\u003e - there is no need to handle empty lists differently from non-empty lists.\n\n### Example: `MultiAsset` (a nested map type)\n\n\u003e The [`cardano-ledger`] library provides the [`MultiAsset`] type, which models a **nested** mapping from [`PolicyID`][`MultiAsset.PolicyID`] keys to [`AssetName`][`MultiAsset.AssetName`] keys to [`Integer`] values:\n\u003e\n\u003e ```hs\n\u003e newtype MultiAsset c = MultiAsset (Map (PolicyID c) (Map AssetName Integer))\n\u003e ```\n\u003e\n\u003e Each [`Integer`] value represents the value of an **asset** on the Cardano blockchain, where each asset is uniquely identified by the combination of a [`PolicyID`][`MultiAsset.PolicyID`] and an [`AssetName`][`MultiAsset.AssetName`]. (Multiple assets can share the same [`PolicyID`][`MultiAsset.PolicyID`].)\n\u003e\n\u003e All [`MultiAsset`] operations maintain a **dual invariant** that:\n\u003e - there must be no mappings from [`PolicyID`][`MultiAsset.PolicyID`] keys to empty maps; and that\n\u003e - there must be no mappings from [`AssetName`][`MultiAsset.AssetName`] keys to [`Integer`] values of `0`.\n\u003e\n\u003e To satisfy this invariant, [`MultiAsset`] operations use a variety of helper functions to ensure that [`MultiAsset`] values are always in a canonical form.\n\u003e\n\u003e For example, consider the [`Semigroup`] instance for [`MultiAsset`]:\n\u003e\n\u003e ```hs\n\u003e instance Semigroup (MultiAsset c) where\n\u003e     MultiAsset m1 \u003c\u003e MultiAsset m2 =\n\u003e         MultiAsset (canonicalMapUnion (canonicalMapUnion (+)) m1 m2)\n\u003e ```\n\u003e\n\u003e The above definition of [`\u003c\u003e`] performs pointwise addition of all pairs of values for matching assets.\n\u003e\n\u003e For example, if:\n\u003e - [`MultiAsset`] `m1` maps asset `a` to a value of `10`;\n\u003e - [`MultiAsset`] `m2` maps asset `a` to a value of `20`;\n\u003e\n\u003e Then:\n\u003e - [`MultiAsset`] `m1 \u003c\u003e m2` will map asset `a` to a value of `30`.\n\u003e\n\u003e The definition of [`\u003c\u003e`] uses a function called [`canonicalMapUnion`][`CanonicalMaps.canonicalMapUnion`], which does the heavy lifting work of performing a union while ensuring that each resulting [`Map`] is in canonical form.\n\u003e\n\u003e Let's have a look at the definition of [`canonicalMapUnion`][`CanonicalMaps.canonicalMapUnion`]:\n\u003e\n\u003e ```hs\n\u003e canonicalMapUnion ::\n\u003e   (Ord k, CanonicalZero a) =\u003e\n\u003e   (a -\u003e a -\u003e a) -\u003e\n\u003e   Map k a -\u003e\n\u003e   Map k a -\u003e\n\u003e   Map k a\n\u003e canonicalMapUnion _f t1 Tip                 = t1\n\u003e canonicalMapUnion  f t1 (Bin _ k x Tip Tip) = canonicalInsert f k x t1\n\u003e canonicalMapUnion  f (Bin _ k x Tip Tip) t2 = canonicalInsert f k x t2\n\u003e canonicalMapUnion _f Tip t2                 = t2\n\u003e canonicalMapUnion  f (Bin _ k1 x1 l1 r1) t2 = case Map.splitLookup k1 t2 of\n\u003e   (l2, mb, r2) -\u003e case mb of\n\u003e     Nothing -\u003e\n\u003e       if x1 == zeroC\n\u003e         then link2 l1l2 r1r2\n\u003e         else link k1 x1 l1l2 r1r2\n\u003e     Just x2 -\u003e\n\u003e       if new == zeroC\n\u003e         then link2 l1l2 r1r2\n\u003e         else link k1 new l1l2 r1r2\n\u003e       where\n\u003e         new = f x1 x2\n\u003e     where\n\u003e       !l1l2 = canonicalMapUnion f l1 l2\n\u003e       !r1r2 = canonicalMapUnion f r1 r2\n\u003e ```\n\u003e\n\u003e The [`canonicalMapUnion`][`CanonicalMaps.canonicalMapUnion`] function in turn relies on [`canonicalInsert`][`CanonicalMaps.canonicalInsert`], which handles individual insertions:\n\u003e\n\u003e ```hs\n\u003e canonicalInsert ::\n\u003e   (Ord k, CanonicalZero a) =\u003e\n\u003e   (a -\u003e a -\u003e a) -\u003e\n\u003e   k -\u003e\n\u003e   a -\u003e\n\u003e   Map k a -\u003e\n\u003e   Map k a\n\u003e canonicalInsert f !kx x = go\n\u003e   where\n\u003e     go Tip = if x == zeroC then Tip else Map.singleton kx x\n\u003e     go (Bin sy ky y l r) =\n\u003e       case compare kx ky of\n\u003e         LT -\u003e link ky y (go l) r\n\u003e         GT -\u003e link ky y l (go r)\n\u003e         EQ -\u003e if new == zeroC then link2 l r else Bin sy kx new l r\n\u003e           where\n\u003e             new = f y x\n\u003e ```\n\u003e\n\u003e Similarly, the [`insertMultiAsset`][`MultiAsset.insertMultiAsset`] function, which \"inserts\" the value of an individual asset into a [`MultiAsset`] value, has the following definition:\n\u003e\n\u003e ```hs\n\u003e insertMultiAsset ::\n\u003e   (Integer -\u003e Integer -\u003e Integer) -\u003e\n\u003e   PolicyID c -\u003e\n\u003e   AssetName -\u003e\n\u003e   Integer -\u003e\n\u003e   MultiAsset c -\u003e\n\u003e   MultiAsset c\n\u003e insertMultiAsset combine pid aid new (MultiAsset m1) =\n\u003e   case Map.splitLookup pid m1 of\n\u003e     (l1, Just m2, l2) -\u003e\n\u003e       case Map.splitLookup aid m2 of\n\u003e         (v1, Just old, v2) -\u003e\n\u003e           if n == 0\n\u003e             then\n\u003e               let m3 = link2 v1 v2\n\u003e                in if Map.null m3\n\u003e                     then MultiAsset (link2 l1 l2)\n\u003e                     else MultiAsset (link pid m3 l1 l2)\n\u003e             else MultiAsset (link pid (link aid n v1 v2) l1 l2)\n\u003e           where\n\u003e             n = combine old new\n\u003e         (_, Nothing, _) -\u003e\n\u003e           MultiAsset\n\u003e             ( link\n\u003e                 pid\n\u003e                 ( if new == 0\n\u003e                     then m2\n\u003e                     else Map.insert aid new m2\n\u003e                 )\n\u003e                 l1\n\u003e                 l2\n\u003e             )\n\u003e     (l1, Nothing, l2) -\u003e\n\u003e       MultiAsset\n\u003e         ( if new == 0\n\u003e             then link2 l1 l2\n\u003e             else link pid (Map.singleton aid new) l1 l2\n\u003e         )\n\u003e ```\n\u003e\n\u003e A notable feature of all the above functions is that they completely eschew the use of [`Map.merge`]. Instead, they directly manipulate constructors exported from [`Map.Internal`]. This approach was probably taken for performance reasons.\n\u003e\n\u003e However, it's clear that maintaining the invariant in this way comes at a **cost**: the code is rather complex, and it were not for a comprehensive test suite, it would probably be very easy to introduce a regression.\n\u003e\n\u003e In the spirit of demonstration, let's see what happens if we redefine the [`MultiAsset`] type in terms of [`MonoidMap`]:\n\u003e\n\u003e ```patch\n\u003e - newtype MultiAsset c = MultiAsset (Map       (PolicyID c) (      Map AssetName      Integer))\n\u003e + newtype MultiAsset c = MultiAsset (MonoidMap (PolicyID c) (MonoidMap AssetName (Sum Integer))\n\u003e ```\n\u003e\n\u003e Note that we have replaced [`Integer`] with \u003ccode\u003e\u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Monoid.html#v:Sum\"\u003eSum\u003c/a\u003e \u003ca href=\"https://hackage.haskell.org/package/base/docs/Prelude.html#t:Integer\"\u003eInteger\u003c/a\u003e\u003c/code\u003e, whose [`Monoid`] instance defines [`mempty`][`Monoid.mempty`] as \u003ccode\u003e\u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Monoid.html#v:Sum\"\u003eSum\u003c/a\u003e 0\u003c/code\u003e, and whose [`Semigroup`] instance defines [`\u003c\u003e`] as equivalent to ordinary integer addition.\n\u003e\n\u003e Recall that all [`MonoidMap`] operations automatically take care of the invariant that values cannot be [`mempty`][`Monoid.mempty`]. For the [`MultiAsset`] type, this means that:\n\u003e - outer maps are now prevented from including any mappings from [`PolicyID`][`MultiAsset.PolicyID`] to empty inner maps.\n\u003e - inner maps are now prevented from including any mappings from [`AssetName`][`MultiAsset.AssetName`] to values of \u003ccode\u003e\u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Monoid.html#v:Sum\"\u003eSum\u003c/a\u003e 0\u003c/code\u003e.\n\u003e\n\u003e As a result, we can remove virtually all code that deals with canonicalisation.\n\u003e\n\u003e For example, we can now simplify the [`Semigroup`] instance for [`MultiAsset`], dispensing entirely with the need to call [`canonicalMapUnion`][`CanonicalMaps.canonicalMapUnion`]:\n\u003e\n\u003e ```patch\n\u003e   instance Semigroup (MultiAsset c) where\n\u003e       MultiAsset m1 \u003c\u003e MultiAsset m2 =\n\u003e -         MultiAsset (canonicalMapUnion (canonicalMapUnion (+)) m1 m2)\n\u003e +         m1 \u003c\u003e m2\n\u003e ```\n\u003e\n\u003e Given that the above instance is trivial, we can even derive the [`Semigroup`] and [`Monoid`] instances automatically:\n\u003e\n\u003e ```patch\n\u003e   newtype MultiAsset c = MultiAsset (MonoidMap (PolicyID c) (MonoidMap AssetName (Sum Integer))\n\u003e +     deriving newtype (Semigroup, Monoid)\n\u003e ```\n\u003e\n\u003e We can also simplify the [`insertMultiAsset`][`MultiAsset.insertMultiAsset`] function:\n\u003e\n\u003e ```patch\n\u003e   insertMultiAsset ::\n\u003e     (Integer -\u003e Integer -\u003e Integer) -\u003e\n\u003e     PolicyID c -\u003e\n\u003e     AssetName -\u003e\n\u003e     Integer -\u003e\n\u003e     MultiAsset c -\u003e\n\u003e     MultiAsset c\n\u003e   insertMultiAsset combine pid aid new (MultiAsset m1) =\n\u003e +   MultiAsset $\n\u003e +   MonoidMap.adjust\n\u003e +     (MonoidMap.adjust (\\(M.Sum old) -\u003e M.Sum (combine old new)) aid) pid m1\n\u003e -  ...\n\u003e -  ### 27 lines deleted ###\n\u003e -  ...\n\u003e ```\n\u003e\n\u003e Finally, since [`MonoidMap`] already provides [`Eq`] and [`Group`] instances that are defined in terms of the underlying monoidal value type, we can automatically derive [`Eq`] and [`Group`] instances for [`MultiAsset`]:\n\u003e\n\u003e ```patch\n\u003e   newtype MultiAsset c = MultiAsset (MonoidMap (PolicyID c) (MonoidMap AssetName (Sum Integer))\n\u003e -     deriving newtype (Semigroup, Monoid)\n\u003e +     deriving newtype (Eq, Semigroup, Monoid, Group)\n\u003e\n\u003e - instance Eq (MultiAsset c) where\n\u003e -   MultiAsset x == MultiAsset y = pointWise (pointWise (==)) x y\n\u003e -\n\u003e - instance Group (MultiAsset c) where\n\u003e -   invert (MultiAsset m) =\n\u003e -     MultiAsset (canonicalMap (canonicalMap ((-1 :: Integer) *)) m)\n\u003e ```\n\u003e\n\u003e Many other simplifications are also possible. (Left as an exercise for readers!)\n\n# Comparison with other generalised map types\n\nThe Haskell ecosystem has several different types for maps with monoidal properties, and several different types that model total functions from keys to values. Each type comes with its own set of advantages and limitations.\n\nHere's a comparison between the [`MonoidMap`] type provided by this library and types provided by other libraries:\n\n\u003ctable\u003e\n\u003cthead\u003e\n  \u003ctr valign=\"top\" align=\"left\"\u003e\n    \u003cth rowspan=\"2\"\u003eType\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003c/th\u003e\n    \u003cth colspan=\"2\"\u003eFeatures\u003c/th\u003e\n    \u003cth colspan=\"5\"\u003eClass Instances\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr valign=\"top\" align=\"left\"\u003e\n    \u003cth\u003e\n      Models\u003cbr/\u003etotal\u003cbr/\u003efunctions\n    \u003c/th\u003e\n    \u003cth\u003e\n      Performs\u003cbr/\u003eautomatic\u003cbr/\u003eminimisation\n    \u003c/th\u003e\n    \u003cth\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Eq.html#t:Eq\"\u003e\n        \u003ccode\u003eEq\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/th\u003e\n    \u003cth\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/monoid-subclasses\"\u003e\n        \u003ccode\u003eMonoid\u003c/code\u003e\u003cbr/\u003e\u003cem\u003esubclasses\u003c/em\u003e\n      \u003c/a\u003e\n    \u003c/th\u003e\n    \u003cth\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/groups/docs/Data-Group.html#t:Group\"\u003e\n        \u003ccode\u003eGroup\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/th\u003e\n    \u003cth\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/base/docs/Data-Functor.html#t:Functor\"\u003e\n        \u003ccode\u003eFunctor\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/th\u003e\n    \u003cth\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/base/docs/Control-Applicative.html#t:Applicative\"\u003e\n        \u003ccode\u003eApplicative\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/th\u003e\n  \u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://github.com/jonathanknowles/monoidmap\"\u003e\n        \u003ccode\u003e\u003cem\u003emonoidmap\u003c/em\u003e\u003c/code\u003e\n      \u003c/a\u003e\n      \u003cbr/\u003e\n      \u003ca href=\"https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#t:MonoidMap\"\u003e\n        \u003ccode\u003eMonoidMap\u003c/code\u003e\n      \u003c/a\u003e\n      \u003cbr/\u003e\n      (this library)\n    \u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/monoid-map\"\u003e\n        \u003ccode\u003e\u003cem\u003emonoid‑map\u003c/em\u003e\u003c/code\u003e\n      \u003c/a\u003e\n      \u003cbr/\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/monoid-map/docs/Data-MonoidMap.html\"\u003e\n        \u003ccode\u003eMonoidMap\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/monoidal-containers\"\u003e\n        \u003ccode\u003e\u003cem\u003emonoidal‑containers\u003c/em\u003e\u003c/code\u003e\n      \u003c/a\u003e\n      \u003cbr/\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/monoidal-containers/docs/Data-Map-Monoidal.html#t:MonoidalMap\"\u003e\n        \u003ccode\u003eMonoidalMap\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/total-map\"\u003e\n        \u003ccode\u003e\u003cem\u003etotal‑map\u003c/em\u003e\u003c/code\u003e\n      \u003c/a\u003e\n      \u003cbr/\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/total-map/docs/Data-TotalMap.html#t:TMap\"\u003e\n        \u003ccode\u003eTMap\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/total-maps\"\u003e\n        \u003ccode\u003e\u003cem\u003etotal‑maps\u003c/em\u003e\u003c/code\u003e\n      \u003c/a\u003e\n      \u003cbr/\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/total-maps/docs/Data-Total-Map-Sparse.html#t:TotalSparseMap\"\u003e\n        \u003ccode\u003eTotalSparseMap\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/defaultable-map\"\u003e\n        \u003ccode\u003e\u003cem\u003edefaultable‑map\u003c/em\u003e\u003c/code\u003e\n      \u003c/a\u003e\n      \u003cbr/\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/defaultable-map/docs/Defaultable-Map.html#t:Defaultable\"\u003e\n        \u003ccode\u003eDefaultableMap\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/chatter\"\u003e\n        \u003ccode\u003e\u003cem\u003echatter\u003c/em\u003e\u003c/code\u003e\n      \u003c/a\u003e\n      \u003cbr/\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/chatter/docs/Data-DefaultMap.html#t:DefaultMap\"\u003e\n        \u003ccode\u003eDefaultMap\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/stack\"\u003e\n        \u003ccode\u003e\u003cem\u003estack\u003c/em\u003e\u003c/code\u003e\n      \u003c/a\u003e\n      \u003cbr/\u003e\n      \u003ca href=\"https://hackage.haskell.org/package/stack/docs/Data-Monoid-Map.html#t:MonoidMap\"\u003e\n        \u003ccode\u003eMonoidMap\u003c/code\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:heavy_check_mark:\u003c/td\u003e\n    \u003ctd\u003e:x:\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n[`cardano-ledger`]: https://github.com/input-output-hk/cardano-ledger\n[`containers`]: https://hackage.haskell.org/package/containers\n[`groups`]: https://hackage.haskell.org/package/groups\n[`monoid-subclasses`]: https://hackage.haskell.org/package/monoid-subclasses\n[`multi-containers`]: https://hackage.haskell.org/package/multi-containers\n[`signed-multiset`]: https://hackage.haskell.org/package/signed-multiset\n\n[`\u003c\u003e`]: https://hackage.haskell.org/package/base/docs/Data-Semigroup.html#v:-60--62-\n[`CanonicalMaps.canonicalInsert`]: https://github.com/input-output-hk/cardano-ledger/blob/b00e28698d9c7fbbeda1c9cfdd1238d3bc4569cf/libs/cardano-data/src/Data/CanonicalMaps.hs#L69\n[`CanonicalMaps.canonicalMapUnion`]: https://github.com/input-output-hk/cardano-ledger/blob/b00e28698d9c7fbbeda1c9cfdd1238d3bc4569cf/libs/cardano-data/src/Data/CanonicalMaps.hs#L42\n[`Eq`]: https://hackage.haskell.org/package/base/docs/Data-Eq.html#t:Eq\n[`Functor`]: https://hackage.haskell.org/package/base/docs/Data-Functor.html#t:Functor\n[`Group`]: https://hackage.haskell.org/package/groups/docs/Data-Group.html#t:Group\n[`Integer`]: https://hackage.haskell.org/package/base/docs/Prelude.html#t:Integer\n[`Map.Internal`]: https://hackage.haskell.org/package/containers/docs/Data-Map-Internal.html\n[`Map.merge`]: https://hackage.haskell.org/package/containers/docs/Data-Map-Merge-Strict.html#v:merge\n[`Map`]: https://hackage.haskell.org/package/containers/docs/Data-Map-Strict.html#t:Map\n[`Maybe`]: https://hackage.haskell.org/package/base/docs/Data-Maybe.html#t:Maybe\n[`Monoid.mempty`]: https://hackage.haskell.org/package/base/docs/Data-Monoid.html#v:mempty\n[`MonoidMap.adjust`]: https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:adjust\n[`MonoidMap.empty`]: https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:empty\n[`MonoidMap.intersection`]: https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:intersection\n[`MonoidMap.invert`]: https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:invert\n[`MonoidMap.map`]: https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:map\n[`MonoidMap.minus`]: https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:minus\n[`MonoidMap.set`]: https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:set\n[`MonoidMap.union`]: https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#v:union\n[`MonoidMap`]: https://jonathanknowles.github.io/monoidmap/Data-MonoidMap.html#t:MonoidMap\n[`MonoidNull.null`]: https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-Null.html#v:null\n[`MonoidNull`]: https://hackage.haskell.org/package/monoid-subclasses/docs/Data-Monoid-Null.html#t:MonoidNull\n[`Monoid`]: https://hackage.haskell.org/package/base/docs/Data-Monoid.html#t:Monoid\n[`MultiAsset.AssetName`]: https://github.com/input-output-hk/cardano-ledger/blob/b00e28698d9c7fbbeda1c9cfdd1238d3bc4569cf/eras/mary/impl/src/Cardano/Ledger/Mary/Value.hs#L110\n[`MultiAsset.PolicyID`]: https://github.com/input-output-hk/cardano-ledger/blob/b00e28698d9c7fbbeda1c9cfdd1238d3bc4569cf/eras/mary/impl/src/Cardano/Ledger/Mary/Value.hs#L140\n[`MultiAsset.insertMultiAsset`]: https://github.com/input-output-hk/cardano-ledger/blob/b00e28698d9c7fbbeda1c9cfdd1238d3bc4569cf/eras/mary/impl/src/Cardano/Ledger/Mary/Value.hs#LL831C1-L868C10\n[`MultiAsset`]: https://github.com/input-output-hk/cardano-ledger/blob/b00e28698d9c7fbbeda1c9cfdd1238d3bc4569cf/eras/mary/impl/src/Cardano/Ledger/Mary/Value.hs#L157\n[`MultiMap.alterWithKey`]: https://hackage.haskell.org/package/multi-containers/docs/Data-Multimap.html#v:alterWithKey\n[`MultiMap`]: https://hackage.haskell.org/package/multi-containers/docs/Data-Multimap.html#t:Multimap\n[`NestedMonoidMap`]: https://github.com/jonathanknowles/monoidmap/blob/main/components/monoidmap-examples/Examples/NestedMonoidMap.hs\n[`NonEmpty`]: https://hackage.haskell.org/package/base/docs/Data-List-NonEmpty.html#t:NonEmpty\n[`Nothing`]: https://hackage.haskell.org/package/base/docs/Data-Maybe.html#v:Nothing\n[`Semigroup`]: https://hackage.haskell.org/package/base/docs/Data-Semigroup.html#t:Semigroup\n[`Set.empty`]: https://hackage.haskell.org/package/containers/docs/Data-Set.html#v:empty\n[`Set.intersection`]: https://hackage.haskell.org/package/containers/docs/Data-Set.html#v:intersection\n[`Set.null`]: https://hackage.haskell.org/package/containers/docs/Data-Set.html#v:null\n[`Set.union`]: https://hackage.haskell.org/package/containers/docs/Data-Set.html#v:union\n[`SetMultiMap.alterWithKey`]: https://hackage.haskell.org/package/multi-containers/docs/Data-Multimap-Set.html#v:alterWithKey\n[`SetMultiMap`]: https://hackage.haskell.org/package/multi-containers/docs/Data-Multimap-Set.html#t:SetMultimap\n[`Set`]: https://hackage.haskell.org/package/containers/docs/Data-Set.html#t:Set\n[`SignedMultiSet.insertMany`]: https://hackage.haskell.org/package/signed-multiset/docs/Data-SignedMultiset.html#v:insertMany\n[`SignedMultiSet`]: https://hackage.haskell.org/package/signed-multiset/docs/Data-SignedMultiset.html#t:SignedMultiset\n[`String`]: https://hackage.haskell.org/package/base/docs/Data-String.html#t:String\n[`Sum`]: https://hackage.haskell.org/package/base/docs/Data-Monoid.html#v:Sum\n[`TMap.trim`]: https://hackage.haskell.org/package/total-map/docs/Data-TotalMap.html#v:trim\n[`TMap`]: https://hackage.haskell.org/package/total-map/docs/Data-TotalMap.html#t:TMap\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathanknowles%2Fmonoidmap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonathanknowles%2Fmonoidmap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathanknowles%2Fmonoidmap/lists"}