| Maintainer | Nickolay Kudasov <nickolay@getshoptv.com> |
|---|---|
| Stability | experimental |
| Safe Haskell | None |
| Language | Haskell2010 |
Data.HashMap.Strict.InsOrd.Compat
Description
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:
InsOrdHashMapvalues 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:
>>>import Data.Aeson (encode, eitherDecode)>>>import qualified Data.ByteString.Lazy.Char8 as BSL8>>>import qualified Data.HashMap.Strict as HM>>>import qualified Data.HashMap.Strict.InsOrd.Compat as IOHM>>>let decodeIOHM s = either error id (eitherDecode (BSL8.pack s) :: Either String (IOHM.InsOrdHashMap String Int))
A regular hash map has no insertion order guarantee:
>>>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:
>>>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.
>>>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.
Synopsis
- data InsOrdHashMap k v
- empty :: InsOrdHashMap k v
- singleton :: Hashable k => k -> v -> InsOrdHashMap k v
- null :: InsOrdHashMap k v -> Bool
- size :: InsOrdHashMap k v -> Int
- member :: Hashable k => k -> InsOrdHashMap k v -> Bool
- lookup :: Hashable k => k -> InsOrdHashMap k v -> Maybe v
- lookupDefault :: Hashable k => v -> k -> InsOrdHashMap k v -> v
- insert :: Hashable k => k -> v -> InsOrdHashMap k v -> InsOrdHashMap k v
- insertWith :: Hashable k => (v -> v -> v) -> k -> v -> InsOrdHashMap k v -> InsOrdHashMap k v
- delete :: Hashable k => k -> InsOrdHashMap k v -> InsOrdHashMap k v
- adjust :: Hashable k => (v -> v) -> k -> InsOrdHashMap k v -> InsOrdHashMap k v
- update :: Hashable k => (v -> Maybe v) -> k -> InsOrdHashMap k v -> InsOrdHashMap k v
- alter :: Hashable k => (Maybe v -> Maybe v) -> k -> InsOrdHashMap k v -> InsOrdHashMap k v
- union :: Hashable k => InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v
- unionWith :: Hashable k => (v -> v -> v) -> InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v
- unionWithKey :: Hashable k => (k -> v -> v -> v) -> InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v
- unions :: Hashable k => [InsOrdHashMap k v] -> InsOrdHashMap k v
- map :: (v -> v) -> InsOrdHashMap k v -> InsOrdHashMap k v
- mapKeys :: Hashable k => (k -> k) -> InsOrdHashMap k v -> InsOrdHashMap k v
- traverseKeys :: (Applicative f, Hashable k) => (k -> f k) -> InsOrdHashMap k v -> f (InsOrdHashMap k v)
- mapWithKey :: (k -> v1 -> v2) -> InsOrdHashMap k v1 -> InsOrdHashMap k v2
- traverseWithKey :: (Applicative f, Hashable k) => (k -> v1 -> f v2) -> InsOrdHashMap k v1 -> f (InsOrdHashMap k v2)
- unorderedTraverse :: (Applicative f, Hashable k) => (v -> f v) -> InsOrdHashMap k v -> f (InsOrdHashMap k v)
- unorderedTraverseWithKey :: (Applicative f, Hashable k) => (k -> v -> f v) -> InsOrdHashMap k v -> f (InsOrdHashMap k v)
- difference :: Hashable k => InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v
- intersection :: Hashable k => InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v
- intersectionWith :: Hashable k => (v -> v -> v) -> InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v
- intersectionWithKey :: Hashable k => (k -> v -> v -> v) -> InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v
- foldl' :: (a -> v -> a) -> a -> InsOrdHashMap k v -> a
- foldlWithKey' :: (a -> k -> v -> a) -> a -> InsOrdHashMap k v -> a
- foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
- foldrWithKey :: (k -> v -> a -> a) -> a -> InsOrdHashMap k v -> a
- foldMapWithKey :: Monoid m => (k -> v -> m) -> InsOrdHashMap k v -> m
- unorderedFoldMap :: Monoid m => (v -> m) -> InsOrdHashMap k v -> m
- unorderedFoldMapWithKey :: Monoid m => (k -> v -> m) -> InsOrdHashMap k v -> m
- filter :: (v -> Bool) -> InsOrdHashMap k v -> InsOrdHashMap k v
- filterWithKey :: (k -> v -> Bool) -> InsOrdHashMap k v -> InsOrdHashMap k v
- mapMaybe :: (v -> Maybe v) -> InsOrdHashMap k v -> InsOrdHashMap k v
- mapMaybeWithKey :: (k -> v -> Maybe v) -> InsOrdHashMap k v -> InsOrdHashMap k v
- keys :: InsOrdHashMap k v -> [k]
- elems :: InsOrdHashMap k v -> [v]
- toList :: InsOrdHashMap k v -> [(k, v)]
- toRevList :: InsOrdHashMap k v -> [(k, v)]
- fromList :: Hashable k => [(k, v)] -> InsOrdHashMap k v
- toHashMap :: InsOrdHashMap k v -> HashMap k v
- fromHashMap :: HashMap k v -> InsOrdHashMap k v
- hashMap :: forall k a b p f. (Profunctor p, Functor f) => p (HashMap k a) (f (HashMap k b)) -> p (InsOrdHashMap k a) (f (InsOrdHashMap k b))
- unorderedTraversal :: forall k a b f. Applicative f => (a -> f b) -> InsOrdHashMap k a -> f (InsOrdHashMap k b)
- valid :: (Eq k, Hashable k) => InsOrdHashMap k v -> Bool
Documentation
data InsOrdHashMap k v Source #
Instances
Construction
empty :: InsOrdHashMap k v Source #
singleton :: Hashable k => k -> v -> InsOrdHashMap k v Source #
Basic interface
null :: InsOrdHashMap k v -> Bool Source #
size :: InsOrdHashMap k v -> Int Source #
lookupDefault :: Hashable k => v -> k -> InsOrdHashMap k v -> v Source #
insert :: Hashable k => k -> v -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
insertWith :: Hashable k => (v -> v -> v) -> k -> v -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
delete :: Hashable k => k -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
adjust :: Hashable k => (v -> v) -> k -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
update :: Hashable k => (v -> Maybe v) -> k -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
alter :: Hashable k => (Maybe v -> Maybe v) -> k -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
Combine
union :: Hashable k => InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
unionWith :: Hashable k => (v -> v -> v) -> InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
unionWithKey :: Hashable k => (k -> v -> v -> v) -> InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
unions :: Hashable k => [InsOrdHashMap k v] -> InsOrdHashMap k v Source #
Transformations
map :: (v -> v) -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
mapKeys :: Hashable k => (k -> k) -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
traverseKeys :: (Applicative f, Hashable k) => (k -> f k) -> InsOrdHashMap k v -> f (InsOrdHashMap k v) Source #
mapWithKey :: (k -> v1 -> v2) -> InsOrdHashMap k v1 -> InsOrdHashMap k v2 Source #
traverseWithKey :: (Applicative f, Hashable k) => (k -> v1 -> f v2) -> InsOrdHashMap k v1 -> f (InsOrdHashMap k v2) Source #
Unordered
unorderedTraverse :: (Applicative f, Hashable k) => (v -> f v) -> InsOrdHashMap k v -> f (InsOrdHashMap k v) Source #
unorderedTraverseWithKey :: (Applicative f, Hashable k) => (k -> v -> f v) -> InsOrdHashMap k v -> f (InsOrdHashMap k v) Source #
Difference and intersection
difference :: Hashable k => InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
intersection :: Hashable k => InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
intersectionWith :: Hashable k => (v -> v -> v) -> InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
intersectionWithKey :: Hashable k => (k -> v -> v -> v) -> InsOrdHashMap k v -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
Folds
foldl' :: (a -> v -> a) -> a -> InsOrdHashMap k v -> a Source #
foldlWithKey' :: (a -> k -> v -> a) -> a -> InsOrdHashMap k v -> a Source #
foldr :: Foldable t => (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 =foldrf z .toList
Examples
Basic usage:
>>>foldr (||) False [False, True, False]True
>>>foldr (||) False []False
>>>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:
>>>foldr (||) False (True : repeat False)True
But the following doesn't terminate:
>>>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):
>>>take 5 $ foldr (\i acc -> i : fmap (+3) acc) [] (repeat 1)[1,4,7,10,13]
foldrWithKey :: (k -> v -> a -> a) -> a -> InsOrdHashMap k v -> a Source #
foldMapWithKey :: Monoid m => (k -> v -> m) -> InsOrdHashMap k v -> m Source #
Unordered
unorderedFoldMap :: Monoid m => (v -> m) -> InsOrdHashMap k v -> m Source #
unorderedFoldMapWithKey :: Monoid m => (k -> v -> m) -> InsOrdHashMap k v -> m Source #
Filter
filter :: (v -> Bool) -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
filterWithKey :: (k -> v -> Bool) -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
mapMaybe :: (v -> Maybe v) -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
mapMaybeWithKey :: (k -> v -> Maybe v) -> InsOrdHashMap k v -> InsOrdHashMap k v Source #
Conversions
keys :: InsOrdHashMap k v -> [k] Source #
elems :: InsOrdHashMap k v -> [v] Source #
toList :: InsOrdHashMap k v -> [(k, v)] Source #
toRevList :: InsOrdHashMap k v -> [(k, v)] Source #
fromList :: Hashable k => [(k, v)] -> InsOrdHashMap k v Source #
toHashMap :: InsOrdHashMap k v -> HashMap k v Source #
fromHashMap :: HashMap k v -> InsOrdHashMap k v Source #
Lenses
hashMap :: forall k a b p f. (Profunctor p, Functor f) => p (HashMap k a) (f (HashMap k b)) -> p (InsOrdHashMap k a) (f (InsOrdHashMap k b)) Source #
This is a slight lie, as roundtrip doesn't preserve ordering.
unorderedTraversal :: forall k a b f. Applicative f => (a -> f b) -> InsOrdHashMap k a -> f (InsOrdHashMap k b) Source #