Skip to content

Commit 39d0064

Browse files
gustywallymathieu
authored andcommitted
+ Missing folds (#622)
1 parent 79d1052 commit 39d0064

File tree

4 files changed

+101
-25
lines changed

4 files changed

+101
-25
lines changed

docsrc/content/abstraction-foldable.fsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ From .Net/F#
5959
- ``list<'T>``
6060
- ``'T []``
6161
- ``option<'T>``
62-
- ``voption<'T>``
62+
- ``voption<'T>``
63+
- ``Result<'T, 'Error>``
6364
- ``ResizeArray<'T>``
6465
- ``ReadOnlyCollection<'T>``
6566
- ``IReadOnlyCollection<'T>``

src/FSharpPlus/Control/Foldable.fs

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,18 @@ open FSharpPlus.Internals.Prelude
4242

4343
type ToSeq =
4444
inherit Default1
45-
static member ToSeq (x: seq<'T> , [<Optional>]_impl: ToSeq) = x
46-
static member ToSeq (x: Text.StringBuilder, _: ToSeq) = string x :> seq<char>
47-
static member ToSeq (x: string , _: ToSeq) = String.toSeq x
48-
static member ToSeq (x: option<'T>, [<Optional>]_impl: ToSeq) = match x with Some x -> Seq.singleton x | _ -> Seq.empty
49-
static member ToSeq (x: Id<'T> , [<Optional>]_impl: ToSeq) = Seq.singleton x.getValue
45+
static member ToSeq (x: seq<'T>, [<Optional>]_impl: ToSeq) =
46+
#if TEST_TRACE
47+
Traces.add "ToSeq seq"
48+
#endif
49+
x
50+
51+
static member ToSeq (x: Text.StringBuilder, _: ToSeq) = string x :> seq<char>
52+
static member ToSeq (x: string , _: ToSeq) = String.toSeq x
53+
static member ToSeq (x: option<'T> , [<Optional>]_impl: ToSeq) = match x with Some x -> Seq.singleton x | _ -> Seq.empty
54+
static member ToSeq (x: voption<'T> , [<Optional>]_impl: ToSeq) = match x with ValueSome x -> Seq.singleton x | _ -> Seq.empty
55+
static member ToSeq (x: Result<'T, _>, [<Optional>]_impl: ToSeq) = match x with Ok x -> Seq.singleton x | _ -> Seq.empty
56+
static member ToSeq (x: Id<'T> , [<Optional>]_impl: ToSeq) = Seq.singleton x.getValue
5057

5158
static member inline Invoke (source: '``Foldable<'T>``) : seq<'T> =
5259
let inline call_2 (a: ^a, b: ^b) = ((^a or ^b) : (static member ToSeq : _*_ -> _) b, a)
@@ -56,7 +63,13 @@ type ToSeq =
5663
static member inline InvokeOnInstance (source: '``Foldable<'T>``) : seq<'T> = (^``Foldable<'T>``: (static member ToSeq : _ -> _) source)
5764

5865
type ToSeq with
59-
static member inline ToSeq (x: 'S when 'S :> Collections.IEnumerable, [<Optional>]_impl: Default2) = let _f i x : 'T = (^S : (member get_Item : int -> 'T) x, i) in Seq.cast<'T> x : seq<'T>
66+
static member inline ToSeq (x: 'S when 'S :> Collections.IEnumerable, [<Optional>]_impl: Default2) =
67+
#if TEST_TRACE
68+
Traces.add "ToSeq IEnumerable"
69+
#endif
70+
let _f i x : 'T = (^S : (member get_Item : int -> 'T) x, i)
71+
Seq.cast<'T> x : seq<'T>
72+
6073
static member inline ToSeq (x: 'Foldable , [<Optional>]_impl: Default1) = ToSeq.InvokeOnInstance x
6174
static member inline ToSeq (_: 'T when 'T: null and 'T: struct , _: Default1) = ()
6275

@@ -99,16 +112,22 @@ type ToArray =
99112

100113
type FoldBack =
101114
inherit Default1
102-
static member inline FoldBack (x: 'F , f: 'a->'b->'b, z: 'b , [<Optional>]_impl: Default2) = List.foldBack f (ToList.Invoke x) z
115+
static member inline FoldBack (x: 'F, f: 'a -> 'b -> 'b, z: 'b, [<Optional>]_impl: Default2) =
116+
#if TEST_TRACE
117+
Traces.add "Foldback Default"
118+
#endif
119+
List.foldBack f (ToList.Invoke x) z
103120
static member inline FoldBack (x: 'F , f: 'a->'b->'b, z: 'b , [<Optional>]_impl: Default1) = (^F : (static member FoldBack : ^F -> _ -> _-> ^b) x, f, z)
104-
static member FoldBack (x: seq<_> , f , z , [<Optional>]_impl: FoldBack) = List.foldBack f (Seq.toList x) z
105-
static member FoldBack (x: option<_> , f , z , [<Optional>]_impl: FoldBack) = match x with Some x -> f x z | _ -> z
121+
static member FoldBack (x: seq<_> , f , z , [<Optional>]_impl: FoldBack) = List.foldBack f (Seq.toList x) z
122+
static member FoldBack (x: option<_> , f , z , [<Optional>]_impl: FoldBack) = match x with Some x -> f x z | _ -> z
123+
static member FoldBack (x: voption<_> , f , z , [<Optional>]_impl: FoldBack) = match x with ValueSome x -> f x z | _ -> z
124+
static member FoldBack (x: Result<_, _> , f , z , [<Optional>]_impl: FoldBack) = match x with Ok x -> f x z | _ -> z
106125
static member FoldBack (x: list<_> , f , z , [<Optional>]_impl: FoldBack) = List.foldBack f x z
107126
static member FoldBack (x: _ [] , f , z , [<Optional>]_impl: FoldBack) = Array.foldBack f x z
108127
static member FoldBack (x: Set<_> , f , z , [<Optional>]_impl: FoldBack) = Set.foldBack f x z
109128
static member FoldBack (x: _ ResizeArray, f , z , [<Optional>]_impl: FoldBack) = Array.foldBack f (x.ToArray ()) z
110129
static member FoldBack (x: string , f , z , [<Optional>]_impl: FoldBack) = Array.foldBack f (x.ToCharArray ()) z
111-
static member FoldBack (x: StringBuilder, f , z , [<Optional>]_impl: FoldBack) = Array.foldBack f (x.ToString().ToCharArray ()) z
130+
static member FoldBack (x: StringBuilder, f , z , [<Optional>]_impl: FoldBack) = Array.foldBack f (x.ToString().ToCharArray ()) z
112131
static member FoldBack (x: Id<'a> , f , z , [<Optional>]_impl: FoldBack) = f x.getValue z
113132

114133
static member inline Invoke (folder: 'T->'State->'State) (state: 'State) (foldable: '``Foldable'<T>``) : 'State =
@@ -122,18 +141,24 @@ type FoldMap =
122141

123142
static member inline FromFoldFoldBack f x = FoldBack.Invoke (Plus.Invoke << f) (Zero.Invoke ()) x
124143

125-
static member inline FoldMap (x: option<_>, f, [<Optional>]_impl: FoldMap ) = match x with Some x -> f x | _ -> Zero.Invoke ()
126-
static member inline FoldMap (x: list<_> , f, [<Optional>]_impl: FoldMap ) = List.fold (fun x y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
127-
static member inline FoldMap (x: Set<_> , f, [<Optional>]_impl: FoldMap ) = Seq.fold (fun x y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
128-
static member inline FoldMap (x: _ [] , f, [<Optional>]_impl: FoldMap ) = Array.fold (fun x y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
144+
static member inline FoldMap (x: option<_> , f, [<Optional>]_impl: FoldMap) = match x with Some x -> f x | _ -> Zero.Invoke ()
145+
static member inline FoldMap (x: voption<_> , f, [<Optional>]_impl: FoldMap) = match x with ValueSome x -> f x | _ -> Zero.Invoke ()
146+
static member inline FoldMap (x: Result<_, _>, f, [<Optional>]_impl: FoldMap) = match x with Ok x -> f x | _ -> Zero.Invoke ()
147+
static member inline FoldMap (x: list<_> , f, [<Optional>]_impl: FoldMap) = List.fold (fun x y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
148+
static member inline FoldMap (x: Set<_> , f, [<Optional>]_impl: FoldMap) = Seq.fold (fun x y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
149+
static member inline FoldMap (x: _ [] , f, [<Optional>]_impl: FoldMap) = Array.fold (fun x y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
129150

130151
static member inline Invoke (f: 'T->'Monoid) (x: '``Foldable'<T>``) : 'Monoid =
131152
let inline call_2 (a: ^a, b: ^b, f) = ((^a or ^b) : (static member FoldMap : _*_*_ -> _) b, f, a)
132153
let inline call (a: 'a, b: 'b, f) = call_2 (a, b, f)
133154
call (Unchecked.defaultof<FoldMap>, x, f)
134155

135156
type FoldMap with
136-
static member inline FoldMap (x: seq<_> , f, [<Optional>]_impl: Default2) = Seq.fold (fun x y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
157+
static member inline FoldMap (x: seq<_> , f, [<Optional>]_impl: Default2) =
158+
#if TEST_TRACE
159+
Traces.add "FoldMap Default"
160+
#endif
161+
Seq.fold (fun x y -> Plus.Invoke x (f y)) (Zero.Invoke ()) x
137162
static member inline FoldMap (x , f, [<Optional>]_impl: Default1) = (^F : (static member FoldMap : ^F -> _ -> _) x, f)
138163
static member inline FoldMap (_: ^t when ^t: null and ^t: struct, _, _: Default1) = ()
139164

@@ -146,14 +171,21 @@ type Fold =
146171

147172
static member inline FromFoldMap f z t = let (f: _Dual<_Endo<'t>>) = FoldMap.Invoke (_Dual << _Endo << flip f) t in f.Value.Value z
148173

149-
static member inline Fold (x , f, z, [<Optional>]_impl: Default2) = Seq.fold f z (ToSeq.Invoke x)
150-
static member inline Fold (x: 'F , f: 'b->'a->'b, z: 'b, [<Optional>]_impl: Default1) = (^F : (static member Fold : ^F -> _ -> _-> ^b) x, f, z)
151-
static member Fold (x: option<_>, f, z , [<Optional>]_impl: Fold ) = match x with Some x -> f z x | _ -> z
152-
static member Fold (x: Id<_> , f, z , [<Optional>]_impl: Fold ) = f z x.getValue
153-
static member Fold (x: seq<_> , f, z , [<Optional>]_impl: Fold ) = Seq.fold f z x
154-
static member Fold (x: list<_> , f, z , [<Optional>]_impl: Fold ) = List.fold f z x
155-
static member Fold (x: Set<_> , f, z , [<Optional>]_impl: Fold ) = Set.fold f z x
156-
static member Fold (x: _ [] , f, z , [<Optional>]_impl: Fold ) = Array.fold f z x
174+
static member inline Fold (x , f, z, [<Optional>]_impl: Default2) =
175+
#if TEST_TRACE
176+
Traces.add "Fold Default"
177+
#endif
178+
Seq.fold f z (ToSeq.Invoke x)
179+
180+
static member inline Fold (x: 'F , f: 'b->'a->'b, z: 'b, [<Optional>]_impl: Default1) = (^F : (static member Fold : ^F -> _ -> _-> ^b) x, f, z)
181+
static member Fold (x: option<_> , f, z , [<Optional>]_impl: Fold ) = match x with Some x -> f z x | _ -> z
182+
static member Fold (x: voption<_> , f, z , [<Optional>]_impl: Fold ) = match x with ValueSome x -> f z x | _ -> z
183+
static member Fold (x: Result<_, _>, f, z , [<Optional>]_impl: Fold ) = match x with Ok x -> f z x | _ -> z
184+
static member Fold (x: Id<_> , f, z , [<Optional>]_impl: Fold ) = f z x.getValue
185+
static member Fold (x: seq<_> , f, z , [<Optional>]_impl: Fold ) = Seq.fold f z x
186+
static member Fold (x: list<_> , f, z , [<Optional>]_impl: Fold ) = List.fold f z x
187+
static member Fold (x: Set<_> , f, z , [<Optional>]_impl: Fold ) = Set.fold f z x
188+
static member Fold (x: _ [] , f, z , [<Optional>]_impl: Fold ) = Array.fold f z x
157189

158190
static member inline Invoke (folder: 'State->'T->'State) (state: 'State) (foldable: '``Foldable'<T>``) : 'State =
159191
let inline call_2 (a: ^a, b: ^b, f, z) = ((^a or ^b) : (static member Fold : _*_*_*_ -> _) b, f, z, a)
@@ -170,7 +202,7 @@ type Exists =
170202
static member Exists (x: 'a [] , f , [<Optional>]_impl: Exists ) = Array.exists f x
171203
static member Exists (x: Set<'a> , f , [<Optional>]_impl: Exists ) = Set.exists f x
172204
static member Exists (x: 'a ResizeArray , f , [<Optional>]_impl: Exists ) = Seq.exists f x
173-
static member Exists (x: string , f , [<Optional>]_impl: Exists ) = String.exists f x
205+
static member Exists (x: string , f , [<Optional>]_impl: Exists ) = String.exists f x
174206
static member Exists (x: StringBuilder , f , [<Optional>]_impl: Exists ) = x |> string |> String.exists f
175207

176208
static member inline Invoke (predicate: 'T->bool) (source: '``Foldable'<T>``) =
@@ -231,6 +263,8 @@ type Head =
231263
static member inline Head (x: '``Foldable<'T>``, [<Optional>]_impl: Default2) = Seq.head (ToSeq.Invoke x) : 'T
232264
static member inline Head (x: '``Foldable<'T>``, [<Optional>]_impl: Default1) = (^``Foldable<'T>`` : (member Head : 'T) x)
233265
static member Head (x: 'T option , [<Optional>]_impl: Head ) = x.Value
266+
static member Head (x: 'T voption , [<Optional>]_impl: Head ) = x.Value
267+
static member Head (x: Result<_, _> , [<Optional>]_impl: Head ) = Result.get x
234268
static member Head (x: 'T [] , [<Optional>]_impl: Head ) = x.[0]
235269
static member Head (x: NonEmptySeq<'T> , [<Optional>]_impl: Head ) = x.First
236270
static member Head (x: Id<'T> , [<Optional>]_impl: Head ) = x.getValue
@@ -390,6 +424,8 @@ type Length =
390424
static member Length (x: ResizeArray<'T> , [<Optional>]_impl: Length ) = x.Count
391425
static member Length (x: 'T list , [<Optional>]_impl: Length ) = List.length x
392426
static member Length (x: option<'T> , [<Optional>]_impl: Length ) = if x.IsSome then 1 else 0
427+
static member Length (x: voption<'T> , [<Optional>]_impl: Length ) = if x.IsSome then 1 else 0
428+
static member Length (x: Result<_, _> , [<Optional>]_impl: Length ) = if Result.isOk x then 1 else 0
393429
static member Length (x: 'T [] , [<Optional>]_impl: Length ) = Array.length x
394430
[<Obsolete;CompiledName("Length")>]
395431
static member LengthLegacy (x:seq<'T> , [<Optional>]_impl:Length) = Seq.length x

tests/FSharpPlus.Tests/FSharpPlus.Tests.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<Compile Include="Splits.fs" />
2323
<Compile Include="Monoid.fs" />
2424
<Compile Include="Parsing.fs" />
25+
<Compile Include="Folds.fs" />
2526
<Compile Include="Traversals.fs" />
2627
<Compile Include="Indexables.fs" />
2728
<Compile Include="Collections.fs" />

tests/FSharpPlus.Tests/Folds.fs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
namespace FSharpPlus.Tests
2+
3+
#nowarn "686"
4+
5+
open System
6+
open System.Collections.ObjectModel
7+
open FSharpPlus
8+
open FSharpPlus.Data
9+
open FSharpPlus.Control
10+
open NUnit.Framework
11+
open Helpers
12+
open FSharpPlus.Math.Applicative
13+
open CSharpLib
14+
open System.Threading.Tasks
15+
#if TEST_TRACE
16+
open FSharpPlus.Internals
17+
#endif
18+
19+
module Folds =
20+
21+
[<Test>]
22+
let basicFolds () =
23+
#if TEST_TRACE
24+
Traces.reset()
25+
#endif
26+
let r1 = set [1..3] |> fold (+) 0
27+
let r2 = set [1..3] |> toSeq
28+
let r3 = ValueSome 1 |> toSeq
29+
let r4 = ValueSome 1 |> fold (+) 0
30+
let r5 = Ok 1 |> fold (+) 0
31+
Assert.AreEqual (6, r1)
32+
CollectionAssert.AreEqual ([1; 2; 3], r2)
33+
CollectionAssert.AreEqual ([1], r3)
34+
Assert.AreEqual (1, r4)
35+
Assert.AreEqual (1, r5)
36+
#if TEST_TRACE
37+
CollectionAssert.AreEqual (["ToSeq seq"], Traces.get())
38+
#endif

0 commit comments

Comments
 (0)