Skip to content

Commit 425e811

Browse files
committed
* improved ComputationExpressions for changeable types
* added `AMap.toASetValues : amap<'k, 'v> -> aset<'v>`
1 parent d1b0e92 commit 425e811

4 files changed

Lines changed: 128 additions & 8 deletions

File tree

src/FSharp.Data.Adaptive/AdaptiveHashMap/AdaptiveHashMap.fs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,57 @@ module AdaptiveHashMapImplementation =
891891

892892

893893
deltas
894+
895+
/// Reader for toASetValues.
896+
type ToValueASetReader<'Key, 'Value>(input : amap<'Key, 'Value>) =
897+
inherit AbstractReader<HashSetDelta<'Value>>(HashSetDelta.empty)
898+
899+
let reader = input.GetReader()
900+
901+
static member DeltaMapping =
902+
fun (oldState : HashMap<'Key, 'Value>) (ops : HashMapDelta<'Key, 'Value>) ->
903+
let mutable deltas = HashSetDelta.empty
904+
for (k,op) in ops do
905+
match op with
906+
| Set v ->
907+
match HashMap.tryFind k oldState with
908+
| None -> ()
909+
| Some oldValue ->
910+
deltas <- HashSetDelta.add (Rem(oldValue)) deltas
911+
deltas <- HashSetDelta.add (Add(v)) deltas
912+
913+
| Remove ->
914+
// NOTE: As it is not clear at what point the toASet computation has been evaluated last, it is
915+
// a valid case that something is removed that is not present in the current local state.
916+
match HashMap.tryFind k oldState with
917+
| None -> ()
918+
| Some ov ->
919+
deltas <- HashSetDelta.add (Rem (ov)) deltas
920+
921+
922+
deltas
923+
924+
override x.Compute(token) =
925+
let oldState = reader.State
926+
let ops = reader.GetChanges token
927+
let mutable deltas = HashSetDelta.empty
928+
for (k,op) in ops do
929+
match op with
930+
| Set v ->
931+
match HashMap.tryFind k oldState with
932+
| None -> ()
933+
| Some oldValue ->
934+
deltas <- HashSetDelta.add (Rem(oldValue)) deltas
935+
deltas <- HashSetDelta.add (Add(v)) deltas
936+
937+
| Remove ->
938+
// NOTE: As it is not clear at what point the toASet computation has been evaluated last, it is
939+
// a valid case that something is removed that is not present in the current local state.
940+
match HashMap.tryFind k oldState with
941+
| None -> ()
942+
| Some ov ->
943+
deltas <- HashSetDelta.add (Rem (ov)) deltas
944+
deltas
894945

895946
/// Reader for mapSet.
896947
type MapSetReader<'Key, 'Value>(set : aset<'Key>, mapping : 'Key -> 'Value) =
@@ -1225,6 +1276,13 @@ module AMap =
12251276
else
12261277
ASet.ofReader (fun () -> ToASetReader(map))
12271278

1279+
/// Creates an aset holding all distinct values from the map.
1280+
let toASetValues (map : amap<'Key, 'Value>) =
1281+
if map.IsConstant then
1282+
ASet.delay (fun () -> map |> force |> HashMap.toSeq |> Seq.map snd |> HashSet.ofSeq)
1283+
else
1284+
ASet.ofReader (fun () -> ToValueASetReader(map))
1285+
12281286
/// Adaptively looks up the given key in the map.
12291287
/// Note that this operation should not be used extensively since its resulting
12301288
/// aval will be re-evaluated upon every change of the map.

src/FSharp.Data.Adaptive/AdaptiveHashMap/AdaptiveHashMap.fsi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ module AMap =
115115

116116
/// Creates an aset holding all key/value tuples from the map.
117117
val toASet : map:amap<'Key,'Value> -> aset<'Key * 'Value>
118+
119+
/// Creates an aset holding all distinct values from the map.
120+
val toASetValues : map:amap<'Key,'Value> -> aset<'Value>
121+
118122

119123
/// Adaptively looks up the given key in the map.
120124
/// Note that this operation should not be used extensively since its resulting

src/FSharp.Data.Adaptive/CollectionExtensions.fs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,11 @@ module CollectionExtensions =
172172
/// Gets the keys of the given map as aset<_>.
173173
let keys (map: amap<'Key, 'Value>) =
174174
if map.IsConstant then
175-
map.Content
176-
|> AVal.force
177-
|> HashMap.keys
178-
|> ASet.ofHashSet
175+
ASet.delay (fun () ->
176+
map.Content
177+
|> AVal.force
178+
|> HashMap.keys
179+
)
179180
else
180181
ASet.ofReader (fun () -> MapKeysReader(map))
181182

@@ -220,6 +221,9 @@ module CollectionExtensions =
220221

221222
/// Creates an aset holding all key/value tuples from the map.
222223
let ofAMap (map: amap<'Key, 'Value>) = AMap.toASet map
224+
225+
/// Creates an aset holding all distinct values from the map.
226+
let ofAMapValues (map: amap<'Key, 'Value>) = AMap.toASetValues map
223227

224228
/// Creates an aset holding all elements of the given list.
225229
let ofAList (list: alist<'T>) =
@@ -396,6 +400,12 @@ module CollectionExtensions =
396400
| None ->
397401
true
398402

403+
module AVal =
404+
let logicalAnd (l : #seq<aval<bool>>) =
405+
Seq.toList l |> BooleanOperators.AdaptiveAnd :> aval<_>
406+
407+
let logicalOr (l : #seq<aval<bool>>) =
408+
Seq.toList l |> BooleanOperators.AdaptiveOr :> aval<_>
399409

400410
/// Adaptive operators for lists.
401411
module List =

src/FSharp.Data.Adaptive/ComputationExpressions.fs

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,18 @@ module ComputationExpressions =
4242
type ASetBuilder() =
4343
member inline x.Yield(value: 'T) = ASet.single value
4444
member inline x.YieldFrom(values: aset<'T>) = values
45+
member inline x.YieldFrom(values: cset<'T>) = values :> aset<_>
4546
member inline x.YieldFrom(values: seq<'T>) = ASet.ofSeq values
4647
member inline x.YieldFrom(values: list<'T>) = ASet.ofList values
4748
member inline x.YieldFrom(values: 'T[]) = ASet.ofArray values
4849
member inline x.YieldFrom(values: HashSet<'T>) = ASet.ofHashSet values
4950

51+
member inline x.YieldFrom(values : alist<'T>) =
52+
ASet.ofAList values
53+
54+
member inline x.YieldFrom(values : amap<'K, 'V>) =
55+
ASet.ofAMap values
56+
5057
member inline x.YieldFrom(values: aval<HashSet<'T>>) =
5158
ASet.ofAVal values
5259

@@ -76,6 +83,15 @@ module ComputationExpressions =
7683
member inline x.For(elements: aset<'T1>, mapping: 'T1 -> aset<'T2>) =
7784
ASet.collect mapping elements
7885

86+
member inline x.For(elements: cset<'T1>, mapping: 'T1 -> aset<'T2>) =
87+
ASet.collect mapping elements
88+
89+
member inline x.For(elements: alist<'T1>, mapping: 'T1 -> aset<'T2>) =
90+
elements |> AList.map mapping |> ASet.ofAList |> ASet.unionMany
91+
92+
member inline x.For(elements: amap<'K, 'V>, mapping: ('K * 'V) -> aset<'T>) =
93+
elements |> AMap.map (fun k v -> mapping(k,v)) |> ASet.ofAMapValues |> ASet.unionMany
94+
7995
member inline x.For(elements: seq<'T1>, mapping: 'T1 -> aset<'T2>) =
8096
elements |> Seq.map mapping |> ASet.ofSeq |> ASet.unionMany
8197

@@ -96,11 +112,23 @@ module ComputationExpressions =
96112
type AListBuilder() =
97113
member inline x.Yield(value: 'T) = AList.single value
98114
member inline x.YieldFrom(values: alist<'T>) = values
115+
member inline x.YieldFrom(values: clist<'T>) = values :> alist<_>
99116
member inline x.YieldFrom(values: seq<'T>) = AList.ofSeq values
100117
member inline x.YieldFrom(values: list<'T>) = AList.ofList values
101118
member inline x.YieldFrom(values: 'T[]) = AList.ofArray values
102119
member inline x.YieldFrom(values: IndexList<'T>) = AList.ofIndexList values
103-
120+
121+
member inline x.YieldFrom(values: aval<IndexList<'T>>) =
122+
AList.ofAVal values
123+
124+
member inline x.YieldFrom(values: aval<seq<'T>>) =
125+
AList.ofAVal (AVal.map IndexList.ofSeq values)
126+
127+
member inline x.YieldFrom(values: aval<list<'T>>) =
128+
AList.ofAVal (AVal.map IndexList.ofList values)
129+
130+
member inline x.YieldFrom(values: aval<array<'T>>) =
131+
AList.ofAVal (AVal.map IndexList.ofArray values)
104132

105133

106134
member inline x.Bind(value: aval<'T1>, mapping: 'T1 -> alist<'T2>) =
@@ -109,6 +137,9 @@ module ComputationExpressions =
109137
member inline x.For(elements: alist<'T1>, mapping: 'T1 -> alist<'T2>) =
110138
AList.collect mapping elements
111139

140+
member inline x.For(elements: clist<'T1>, mapping: 'T1 -> alist<'T2>) =
141+
AList.collect mapping elements
142+
112143
member inline x.For(elements: seq<'T1>, mapping: 'T1 -> alist<'T2>) =
113144
elements |> Seq.map mapping |> AList.concat
114145

@@ -146,6 +177,7 @@ module ComputationExpressions =
146177

147178
member inline x.YieldFrom(value: aval<HashMap<'Key, 'Value>>) = AMap.ofAVal value
148179
member inline x.YieldFrom(map: amap<'Key, 'Value>) = map
180+
member inline x.YieldFrom(map: cmap<'Key, 'Value>) = map :> amap<_,_>
149181
member inline x.YieldFrom(map: HashMap<'Key, 'Value>) = AMap.ofHashMap map
150182
member inline x.YieldFrom(map: ('Key * 'Value) seq) = AMap.ofSeq map
151183
member inline x.YieldFrom(map: ('Key * 'Value) list) = AMap.ofList map
@@ -172,14 +204,21 @@ module ComputationExpressions =
172204
/// tests if some ComputationExpressions compile
173205
module private Test =
174206

175-
let set (e : aval<int>) (some : aval<list<string>>) (set : aset<int>) =
207+
let set (e : aval<int>) (some : aval<list<int>>) (set : aset<int>) (c : cset<int>) (m : amap<int, string>) =
176208
aset {
177209
yield 1337
210+
211+
yield! c
212+
yield! AMap.keys m
178213

214+
yield! some
179215
yield! (AVal.map Seq.singleton e)
180216
yield! (AVal.map List.singleton e)
181217
yield! (AVal.map Array.singleton e)
182218
yield! (AVal.map HashSet.single e)
219+
220+
for v in c do
221+
yield v
183222

184223
for v in set do
185224
yield v
@@ -195,22 +234,31 @@ module ComputationExpressions =
195234
()
196235
}
197236

198-
let list (e : aval<int>) (some : aval<list<string>>) (list : alist<int>) =
237+
let list (e : aval<int>) (some : aval<list<int>>) (list : alist<int>) (c : clist<int>) =
199238
alist {
200239
yield 1
201240

241+
yield! c
242+
yield! list
243+
yield! some
244+
245+
for e in c do
246+
yield 2*e
247+
202248
for e in list do
203249
yield! [2*e; 2*e+1]
204250

205251
let! v = e
206252
()
207253
}
208254

209-
let map (k : aval<int>) (v : aval<string>) =
255+
let map (k : aval<int>) (v : aval<string>) (c : cmap<int, string>) =
210256
amap {
211257
// yield constant key and value
212258
yield (1, "one")
213259

260+
yield! c
261+
214262
// yield adaptive tuple
215263
yield! (k |> AVal.map (fun v -> v, string v))
216264

0 commit comments

Comments
 (0)