Skip to content

Commit d2c4341

Browse files
committed
+ Folds
1 parent e6f1949 commit d2c4341

File tree

4 files changed

+119
-2
lines changed

4 files changed

+119
-2
lines changed

src/FSharpPlus/Control/Foldable.fs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@ type FoldMap =
147147
static member inline FoldMap (x: Set<_> , f, [<Optional>]_impl: FoldMap) = Seq.fold (fun x y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
148148
static member inline FoldMap (x: _ [] , f, [<Optional>]_impl: FoldMap) = Array.fold (fun x y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
149149

150+
static member inline FoldMap (x: Map<_, _> , f, [<Optional>]_impl: FoldMap) = Map.fold (fun x _ y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
151+
static member inline FoldMap (x: Dictionary<_, _> , f, [<Optional>]_impl: FoldMap) = Dictionary.fold (fun x _ y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
152+
static member inline FoldMap (x: IDictionary<_, _> , f, [<Optional>]_impl: FoldMap) = Dict.fold (fun x _ y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
153+
static member inline FoldMap (x: IReadOnlyDictionary<_, _>, f, [<Optional>]_impl: FoldMap) = IReadOnlyDictionary.fold (fun x _ y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
154+
150155
static member inline Invoke (f: 'T->'Monoid) (x: '``Foldable'<T>``) : 'Monoid =
151156
let inline call_2 (a: ^a, b: ^b, f) = ((^a or ^b) : (static member FoldMap : _*_*_ -> _) b, f, a)
152157
let inline call (a: 'a, b: 'b, f) = call_2 (a, b, f)
@@ -185,6 +190,10 @@ type Fold =
185190
static member Fold (x: list<_> , f, z , [<Optional>]_impl: Fold ) = List.fold f z x
186191
static member Fold (x: Set<_> , f, z , [<Optional>]_impl: Fold ) = Set.fold f z x
187192
static member Fold (x: _ [] , f, z , [<Optional>]_impl: Fold ) = Array.fold f z x
193+
static member Fold (x: Map<_,_> , f, z , [<Optional>]_impl: Fold ) = Map.fold (fun s _ -> f s) z x
194+
static member Fold (x: Dictionary<_,_> , f, z , [<Optional>]_impl: Fold ) = Dictionary.fold (fun s _ -> f s) z x
195+
static member Fold (x: IDictionary<_,_> , f, z , [<Optional>]_impl: Fold ) = Dict.fold (fun s _ -> f s) z x
196+
static member Fold (x: IReadOnlyDictionary<_,_>, f, z , [<Optional>]_impl: Fold ) = IReadOnlyDictionary.fold (fun s _ -> f s) z x
188197

189198
static member inline Invoke (folder: 'State->'T->'State) (state: 'State) (foldable: '``Foldable'<T>``) : 'State =
190199
let inline call_2 (a: ^a, b: ^b, f, z) = ((^a or ^b) : (static member Fold : _*_*_*_ -> _) b, f, z, a)

src/FSharpPlus/Extensions/Dict.fs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,3 +268,42 @@ module Dict =
268268
| Some v -> dct.Add (k, v)
269269
| None -> ()
270270
dct :> IDictionary<'Key, 'U>
271+
272+
/// <summary>Creates an empty dictionary.</summary>
273+
[<GeneralizableValue>]
274+
let empty<'Key, 'U when 'Key : equality> = Dictionary<'Key, 'U> () :> IDictionary<_,_>
275+
276+
/// <summary>Converts a dictionary to a ResizeArray.</summary>
277+
/// <param name="source">The source dictionary.</param>
278+
///
279+
/// <returns>A ResizeArray containing the Key and Value of the original dictionary.</returns>
280+
let toResizeArray (source: IDictionary<'Key, 'T>) =
281+
let arr = ResizeArray<KeyValuePair<'Key, 'T>> ()
282+
for KeyValue (k, x) in source do
283+
arr.Add (KeyValuePair (k, x))
284+
arr
285+
286+
/// <summary>Converts a dictionary to a sequence.</summary>
287+
/// <param name="source">The source dictionary.</param>
288+
///
289+
/// <returns>A sequence containing the Key and Value of the original dictionary.</returns>
290+
let toSeq (source: IDictionary<'Key, 'T>) = toResizeArray source :> seq<_>
291+
292+
/// <summary>Folds over the bindings in the dictionary.</summary>
293+
/// <remarks>
294+
/// This function takes a folder function, an initial state, and a source dictionary.
295+
/// The folder function is applied to each key-value pair in the source, accumulating a state.
296+
/// The initial state is provided as the first argument to the folder function.
297+
/// The function returns the final accumulated state after processing all key-value pairs.
298+
/// </remarks>
299+
/// <param name="folder">The folder function that takes the current state, a key, and a value, and returns the new state.</param>
300+
/// <param name="state">The initial state to start the folding process.</param>
301+
/// <param name="source">The source dictionary to fold over.</param>
302+
/// <typeparam name="'State">The type of the state being accumulated.</typeparam>
303+
/// <typeparam name="'Key">The type of the keys in the dictionary.</typeparam>
304+
/// <typeparam name="'T">The type of the values in the dictionary.</typeparam>
305+
///
306+
/// <returns>The final accumulated state after folding over all key-value pairs in the source.</returns>
307+
let fold (folder: 'State -> 'Key -> 'T -> 'State) (state: 'State) (source: IDictionary<'Key, 'T>) =
308+
let unzip source = Seq.map fst source, Seq.map snd source
309+
source |> toSeq |> Seq.map (|KeyValue|) |> unzip ||> Seq.fold2 folder state

src/FSharpPlus/Extensions/Dictionary.fs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,42 @@ module Dictionary =
269269
| Some v -> dct.Add (k, v)
270270
| None -> ()
271271
dct
272+
273+
/// <summary>Creates an empty dictionary.</summary>
274+
[<GeneralizableValue>]
275+
let empty<'Key, 'U when 'Key : equality> = Dictionary<'Key, 'U> ()
276+
277+
/// <summary>Converts a dictionary to a ResizeArray.</summary>
278+
/// <param name="source">The source dictionary.</param>
279+
///
280+
/// <returns>A ResizeArray containing the Key and Value of the original dictionary.</returns>
281+
let toResizeArray (source: Dictionary<'Key, 'T>) =
282+
let arr = ResizeArray<KeyValuePair<'Key, 'T>> ()
283+
for KeyValue (k, x) in source do
284+
arr.Add (KeyValuePair (k, x))
285+
arr
286+
287+
/// <summary>Converts a dictionary to a sequence.</summary>
288+
/// <param name="source">The source dictionary.</param>
289+
///
290+
/// <returns>A sequence containing the Key and Value of the original dictionary.</returns>
291+
let toSeq (source: Dictionary<'Key, 'T>) = toResizeArray source :> seq<_>
292+
293+
/// <summary>Folds over the bindings in the dictionary.</summary>
294+
/// <remarks>
295+
/// This function takes a folder function, an initial state, and a source dictionary.
296+
/// The folder function is applied to each key-value pair in the source, accumulating a state.
297+
/// The initial state is provided as the first argument to the folder function.
298+
/// The function returns the final accumulated state after processing all key-value pairs.
299+
/// </remarks>
300+
/// <param name="folder">The folder function that takes the current state, a key, and a value, and returns the new state.</param>
301+
/// <param name="state">The initial state to start the folding process.</param>
302+
/// <param name="source">The source dictionary to fold over.</param>
303+
/// <typeparam name="'State">The type of the state being accumulated.</typeparam>
304+
/// <typeparam name="'Key">The type of the keys in the dictionary.</typeparam>
305+
/// <typeparam name="'T">The type of the values in the dictionary.</typeparam>
306+
///
307+
/// <returns>The final accumulated state after folding over all key-value pairs in the source.</returns>
308+
let fold (folder: 'State -> 'Key -> 'T -> 'State) (state: 'State) (source: Dictionary<'Key, 'T>) =
309+
let unzip source = Seq.map fst source, Seq.map snd source
310+
source |> toSeq |> Seq.map (|KeyValue|) |> unzip ||> Seq.fold2 folder state

src/FSharpPlus/Extensions/IReadOnlyDictionary.fs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ module IReadOnlyDictionary =
299299

300300
#endif
301301

302+
/// <summary>Creates an empty read-only dictionary.</summary>
303+
[<GeneralizableValue>]
302304
let empty<'Key, 'U when 'Key : equality> = Dictionary<'Key, 'U> () :> IReadOnlyDictionary<_,_>
303305

304306
/// <summary>Converts a read-only dictionary to a ResizeArray.</summary>
@@ -317,12 +319,40 @@ module IReadOnlyDictionary =
317319
/// <returns>A sequence containing the Key and Value of the original IReadOnlyDictionary.</returns>
318320
let toSeq (source: IReadOnlyDictionary<'Key, 'T>) = toResizeArray source :> seq<_>
319321

320-
/// Folds over the bindings in the Dictionary
322+
/// <summary>Folds over the bindings in the Dictionary.</summary>
323+
/// <remarks>
324+
/// This function takes a folder function, an initial state, and a source read-only dictionary.
325+
/// The folder function is applied to each key-value pair in the source, accumulating a state.
326+
/// The initial state is provided as the first argument to the folder function.
327+
/// The function returns the final accumulated state after processing all key-value pairs.
328+
/// </remarks>
329+
/// <param name="folder">The folder function that takes the current state, a key, and a value, and returns the new state.</param>
330+
/// <param name="state">The initial state to start the folding process.</param>
331+
/// <param name="source">The source read-only dictionary to fold over.</param>
332+
/// <typeparam name="'State">The type of the state being accumulated.</typeparam>
333+
/// <typeparam name="'Key">The type of the keys in the read-only dictionary.</typeparam>
334+
/// <typeparam name="'T">The type of the values in the read-only dictionary.</typeparam>
335+
///
336+
/// <returns>The final accumulated state after folding over all key-value pairs in the source.</returns>
321337
let fold (folder: 'State -> 'Key -> 'T -> 'State) (state: 'State) (source: IReadOnlyDictionary<'Key, 'T>) =
322338
let unzip source = Seq.map fst source, Seq.map snd source
323339
source |> toSeq |> Seq.map (|KeyValue|) |> unzip ||> Seq.fold2 folder state
324340

325-
/// Folds over the bindings in the Dictionary
341+
/// <summary>Folds over the bindings in the Dictionary in reverse order.</summary>
342+
/// <remarks>
343+
/// This function takes a folder function, a source read-only dictionary, and an initial state.
344+
/// The folder function is applied to each key-value pair in the source, accumulating a state.
345+
/// The initial state is provided as the last argument to the folder function.
346+
/// The function returns the final accumulated state after processing all key-value pairs.
347+
/// </remarks>
348+
/// <param name="folder">The folder function that takes a key, a value, and the current state, and returns the new state.</param>
349+
/// <param name="source">The source read-only dictionary to fold over.</param>
350+
/// <param name="state">The initial state to start the folding process.</param>
351+
/// <typeparam name="'State">The type of the state being accumulated.</typeparam>
352+
/// <typeparam name="'Key">The type of the keys in the read-only dictionary.</typeparam>
353+
/// <typeparam name="'T">The type of the values in the read-only dictionary.</typeparam>
354+
///
355+
/// <returns>The final accumulated state after folding over all key-value pairs in the source.</returns>
326356
let foldBack (folder: 'Key -> 'T -> 'State -> 'State) (source: IReadOnlyDictionary<'Key, 'T>) state =
327357
let unzip source = Seq.map fst source, Seq.map snd source
328358
source |> toSeq |> Seq.map (|KeyValue|) |> unzip ||> Seq.foldBack2 folder <| state

0 commit comments

Comments
 (0)