-
Notifications
You must be signed in to change notification settings - Fork 199
/
Map.daml
196 lines (160 loc) · 6.06 KB
/
Map.daml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
-- Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
-- SPDX-License-Identifier: Apache-2.0
{-# LANGUAGE CPP #-}
#ifdef DAML_GENMAP
-- | `DA.Next.Map` is deprecated. Please use `DA.Map` instead.
module DA.Next.Map
{-# DEPRECATED "DA.Next.Map is deprecated. Please use DA.Map instead." #-}
#else
-- | Map - A `Map` is an associative array data type composed of a
-- collection of key/value pairs such that each possible key appears
-- at most once in the collection.
module DA.Next.Map
#endif
( Map
, MapKey (..)
, empty
, size
, toList
, fromList
, fromListWith
, toTextMap
, fromTextMap
, null
, lookup
, member
, filter
, filterWithKey
, delete
, insert
, union
, merge
) where
import Prelude hiding (lookup, null, filter, empty)
import DA.Foldable qualified as Foldable
import DA.Text
import DA.TextMap (TextMap)
import DA.TextMap qualified as TextMap
import DA.Traversable qualified as Traversable
import DA.Tuple
-- | A `Map k v` is an associative array data type composed of a
-- collection of key/value pairs of key type `k` and value type `v`
-- such that each possible key appears at most once in the collection.
newtype Map k v = Map with textMap : TextMap v
deriving (Eq, Ord, Foldable.Foldable)
-- | A class for types that can be used as keys for the `Map` type.
-- All keys `k` must satisfy `keyFromText (keyToText k) == k`.
class Eq k => MapKey k where
-- | Turn a key into its textual representation. This function must be
-- injective.
keyToText : k -> Text
-- | Recover a key from its textual representation. `keyFromText x` is
-- allowed to fail whenever there is _no_ key `k` with `keyToText k == x`.
-- Whenever such a `k` does exist, then it must satisfy
-- `keyFromText x == k`.
keyFromText : Text -> k
instance MapKey Text where
keyToText x = x
keyFromText x = x
keyFromTextNote : Text -> Text -> Text
keyFromTextNote target t =
"keyFromText: could not parse " <> show t <> " as '" <> target <> "'"
instance MapKey Party where
keyToText = partyToText
keyFromText t =
case partyFromText t of
None -> error (keyFromTextNote "Party" t)
Some x -> x
instance MapKey Int where
keyToText = show
keyFromText t =
case parseInt t of
None -> error (keyFromTextNote "Int" t)
Some x -> x
instance MapKey Decimal where
keyToText = show
keyFromText t =
case parseDecimal t of
None -> error (keyFromTextNote "Decimal" t)
Some x -> x
-- | Create a map from a list of key/value pairs.
fromList : MapKey k => [(k, v)] -> Map k v
fromList kvs = Map $ TextMap.fromList $ map (first keyToText) kvs
-- | Create a map from a list of key/value pairs with a combining
-- function. Examples:
-- ```
-- fromListWith (<>) [(5,"a"), (5,"b"), (3,"b"), (3,"a"), (5,"c")] == fromList [(3, "ba"), (5, "abc")]
-- fromListWith (<>) [] == (empty : Map Int Text)
-- ```
fromListWith : MapKey k => (v -> v -> v) -> [(k, v)] -> Map k v
fromListWith f kvs = Map $ TextMap.fromListWith f $ map (first keyToText) kvs
-- | Convert the map to a list of key/value pairs where the keys are
-- in ascending order of their textual representation.
toList : MapKey k => Map k v -> [(k, v)]
toList (Map t) = map (first keyFromText) $ TextMap.toList t
-- | Create a `Map` from a `TextMap`.
fromTextMap : TextMap v -> Map Text v
fromTextMap = Map
-- | Convert a `Map` into a `TextMap`.
toTextMap : MapKey k => Map k v -> TextMap v
toTextMap (Map t) = t
-- | The empty map.
empty : Map k v
empty = Map TextMap.empty
-- | Number of elements in the map.
size : Map k v -> Int
size (Map t) = TextMap.size t
-- | Is the map empty?
null : Map k v -> Bool
null m = size m == 0
-- | Lookup the value at a key in the map.
lookup : MapKey k => k -> Map k v -> Optional v
lookup k (Map t) = TextMap.lookup (keyToText k) t
-- | Is the key a member of the map?
member : MapKey k => k -> Map k v -> Bool
member k (Map t) = TextMap.member (keyToText k) t
-- | Filter the `Map` using a predicate: keep only the entries where the
-- value satisfies the predicate.
filter : MapKey k => (v -> Bool) -> Map k v -> Map k v
filter p = filterWithKey (const p)
-- | Filter the `Map` using a predicate: keep only the entries which
-- satisfy the predicate.
filterWithKey : MapKey k => (k -> v -> Bool) -> Map k v -> Map k v
filterWithKey p (Map t) = Map $ TextMap.filterWithKey (p . keyFromText) t
-- | Delete a key and its value from the map. When the key is not a
-- member of the map, the original map is returned.
delete : MapKey k => k -> Map k v -> Map k v
delete k (Map t) = Map $ TextMap.delete (keyToText k) t
-- | Insert a new key/value pair in the map. If the key is already
-- present in the map, the associated value is replaced with the
-- supplied value.
insert : MapKey k => k -> v -> Map k v -> Map k v
insert k v (Map t) = Map $ TextMap.insert (keyToText k) v t
-- | The union of two maps, preferring the first map when equal
-- keys are encountered.
union : MapKey k => Map k v -> Map k v -> Map k v
union (Map t1) (Map t2) = Map $ TextMap.union t1 t2
-- | Merge two maps. `merge f g h x y` applies `f` to all key/value pairs
-- whose key only appears in `x`, `g` to all pairs whose key only appears
-- in `y` and `h` to all pairs whose key appears in both `x` and `y`.
-- In the end, all pairs yielding `Some` are collected as the result.
merge
: MapKey k
=> (k -> a -> Optional c)
-> (k -> b -> Optional c)
-> (k -> a -> b -> Optional c)
-> Map k a
-> Map k b
-> Map k c
merge f g h (Map xs) (Map ys) = Map $ TextMap.merge (f . keyFromText) (g . keyFromText) (h . keyFromText) xs ys
instance (MapKey k, Show k, Show v) => Show (Map k v) where
show m = "Map " <> show (toList m)
deriving instance MapKey k => Semigroup (Map k v)
-- TODO(MH): The converter to Daml-LF can't handle deriving this right now.
-- It fails with "Coercion with symco."
-- deriving instance MapKey k => Monoid (Map k v)
instance MapKey k => Monoid (Map k v) where
mempty = empty
deriving instance MapKey k => Functor (Map k)
instance MapKey k => Traversable.Traversable (Map k) where
mapA f (Map t) = fmap Map $ Traversable.mapA f t