HORIZON HASKELLDocslts/ghc-10.0.xfc4e5982026-10-11Search names, modules, packages, or :: a typeCtrl K

GHC 10.0.0.20260917 · lts/ghc-10.0.x · fc4e598 · 2026-10-11

Moduleopenapi3-3.2.5Haskell2010

Data.HashMap.Strict.InsOrd.Compat

Compatibility wrapper around insert-ordered-containers to mitigate the breaking changes introduced in insert-ordered-containers-0.3.0: https://github.com/erikd/insert-ordered-containers/pull/8.

That change fixed Eq and Aeson instances in the upstream package, but it is a behavioral break for swagger2 where we need stable Swagger Schema generation and JSON object-like encoding.

This module keeps the old swagger2 expectations:

  • InsOrdHashMap values are encoded as JSON objects (not arrays of key/value tuples), so field names remain first-class object keys.

  • Equality intentionally ignores insertion order (compares as plain hash maps), which matches how many tests currently assert JSON equality.

Simple encoding examples:

Example5 expressions
import Data.Aeson (encode, eitherDecode)import qualified Data.ByteString.Lazy.Char8 as BSL8import qualified Data.HashMap.Strict as HMimport qualified Data.HashMap.Strict.InsOrd.Compat as IOHMlet decodeIOHM s = either error id (eitherDecode (BSL8.pack s) :: Either String (IOHM.InsOrdHashMap String Int))

A regular hash map has no insertion order guarantee:

Example2 expressions
encode (HM.fromList [("a", 1 :: Int), ("b", 2)])"{\"a\":1,\"b\":2}"encode (HM.fromList [("b", 1 :: Int), ("a", 2)])"{\"a\":2,\"b\":1}"

Our compat InsOrdHashMap encodes to a JSON object as well, but preserves insertion order:

Example2 expressions
encode (IOHM.fromList [("a", 1 :: Int), ("b", 2)])"{\"a\":1,\"b\":2}"encode (IOHM.fromList [("b", 1 :: Int), ("a", 2)])"{\"b\":1,\"a\":2}"

Round-tripping through decode/encode demonstrates the caveat: encoding preserves insertion order, but decoded object key order is not guaranteed.

Example2 expressions
encode (decodeIOHM "{\"a\":1,\"b\":2}")"{\"a\":1,\"b\":2}"encode (decodeIOHM "{\"b\":1,\"a\":2}")"{\"a\":2,\"b\":1}"

This object encoding is what swagger2 wants for generated Swagger definitions/properties because it keeps emitted schemas easy to consume and stable in practice.

Important caveat: decoding cannot be fully stable with respect to insertion order due to aeson limitations. In particular, object parsing goes through structures that do not preserve all ordering guarantees end-to-end. We accept this trade-off for now because the primary requirement is deterministic encoding for generated Swagger Schema artifacts.

Many tests rely on aesonQQ-style JSON equality, where semantic object equality matters more than insertion order. Comparing via plain hash maps makes those tests robust under benign key-order variation. This is a weaker notion of equality and hopefully will be revisited later.

  • 1 type
  • 48 values
  • Packageopenapi3-3.2.5
  • Exports50
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceCompat.hs
newtypenewtype InsOrdHashMap k v
#
Instances54FoldableWithIndex, FunctorWithIndex, TraversableWithIndex, HasRequestBodies, HasSchemas, HasCallbacks, …

Construction

2 declarations

Basic interface

11 declarations

Combine

4 declarations

Transformations

5 declarations

Unordered

Difference and intersection

4 declarations

Folds

5 declarations
methodfoldr :: (a -> b -> b) -> b -> t a -> b
#

Right-associative fold of a structure, lazy in the accumulator.

In the case of lists, foldr, when applied to a binary operator, a starting value (typically the right-identity of the operator), and a list, reduces the list using the binary operator, from right to left:

foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)

Note that since the head of the resulting expression is produced by an application of the operator to the first element of the list, given an operator lazy in its right argument, foldr can produce a terminating expression from an unbounded list.

For a general Foldable structure this should be semantically identical to,

foldr f z = foldr f z . toList
Examples

Basic usage:

Example1 expression
foldr (||) False [False, True, False]True
Example1 expression
foldr (||) False []False
Example1 expression
foldr (\c acc -> acc ++ [c]) "foo" ['a', 'b', 'c', 'd']"foodcba"
Infinite structures

⚠️ Applying foldr to infinite structures usually doesn't terminate.

It may still terminate under one of the following conditions:

  • the folding function is short-circuiting

  • the folding function is lazy on its second argument

Short-circuiting

(||) short-circuits on True values, so the following terminates because there is a True value finitely far from the left side:

Example1 expression
foldr (||) False (True : repeat False)True

But the following doesn't terminate:

Example1 expression
foldr (||) False (repeat False ++ [True])* Hangs forever *
Laziness in the second argument

Applying foldr to infinite structures terminates when the operator is lazy in its second argument (the initial accumulator is never used in this case, and so could be left undefined, but [] is more clear):

Example1 expression
take 5 $ foldr (\i acc -> i : fmap (+3) acc) [] (repeat 1)[1,4,7,10,13]

Unordered

Filter

4 declarations

Conversions

7 declarations

Lenses

2 declarations

Debugging

1 declaration