Skip to content

Commit 9ce1279

Browse files
author
Rafał Gwoździński
authoredFeb 23, 2021
Evaluate traverse left to right (#418)
1 parent 4dbb62e commit 9ce1279

File tree

3 files changed

+34
-7
lines changed

3 files changed

+34
-7
lines changed
 

‎src/FSharpPlus/Control/Traversable.fs

+18-7
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ type Traverse =
8181
static member inline Traverse (t: option<_>, f, [<Optional>]_output: 'R, [<Optional>]_impl: Traverse) : 'R = match t with Some x -> Map.Invoke Some (f x) | _ -> result None
8282

8383
static member inline Traverse (t:Map<_,_> , f, [<Optional>]_output: 'R, [<Optional>]_impl: Traverse) : 'R =
84-
let insert_f k x ys = Map.Invoke (Map.add k) (f x) <*> ys
85-
Map.foldBack insert_f t (result Map.empty)
84+
let insert_f m k v = Map.Invoke (Map.add k) v <*> m
85+
Map.fold insert_f (result Map.empty) (Map.mapValues f t)
8686

8787
static member inline Traverse (t: Result<'T,'Error>, f: 'T->'``Functor<'U>``, [<Optional>]_output: '``Functor<Result<'U,'Error>>``, [<Optional>]_impl: Traverse) : '``Functor<Result<'U,'Error>>`` =
8888
match t with
@@ -95,13 +95,24 @@ type Traverse =
9595
| Choice2Of2 e -> Return.Invoke (Choice<'U,'Error>.Choice2Of2 e)
9696

9797
static member inline Traverse (t:list<_> ,f , [<Optional>]_output: 'R, [<Optional>]_impl: Traverse) : 'R =
98-
let cons_f x ys = Map.Invoke List.cons (f x) <*> ys
99-
List.foldBack cons_f t (result [])
98+
let rec loop acc = function
99+
| [] -> acc
100+
| x::xs ->
101+
let v = f x
102+
loop (v::acc) xs
103+
let cons_f x xs = Map.Invoke List.cons xs <*> x
104+
List.fold cons_f (result []) (loop [] t)
100105

101106
static member inline Traverse (t:_ [] ,f , [<Optional>]_output: 'R, [<Optional>]_impl: Traverse) : 'R =
102-
let cons x y = Array.append [|x|] y
103-
let cons_f x ys = Map.Invoke cons (f x) <*> ys
104-
Array.foldBack cons_f t (result [||])
107+
let cons x y = Array.append [|x|] y
108+
let rec loop acc = function
109+
| [||] -> acc
110+
| xxs ->
111+
let x, xs = Array.head xxs, Array.tail xxs
112+
let v = f x
113+
loop (cons v acc) xs
114+
let cons_f x xs = Map.Invoke cons xs <*> x
115+
Array.fold cons_f (result [||]) (loop [||] t)
105116

106117
static member inline Invoke (f: 'T->'``Functor<'U>``) (t: '``Traversable<'T>``) : '``Functor<'Traversable<'U>>`` =
107118
let inline call_3 (a: ^a, b: ^b, c: ^c, f) = ((^a or ^b or ^c) : (static member Traverse : _*_*_*_ -> _) b, f, c, a)

‎tests/FSharpPlus.Tests/General.fs

+8
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,14 @@ module Traversable =
12611261
let _ = Seq.sequence [ZipList [1]; ZipList []; ZipList (seq {failwith "sholdn't get here"})] |> toList
12621262
()
12631263

1264+
[<Test>]
1265+
let traverse_Order () =
1266+
SideEffects.reset()
1267+
let mapper v = SideEffects.add <| sprintf "mapping %d" v
1268+
let _ = traverse (Option.map mapper) [Some 1; Some 2]
1269+
SideEffects.are ["mapping 1"; "mapping 2"]
1270+
1271+
12641272
[<Test>]
12651273
let traversableForNonPrimitive () =
12661274
let nel = nelist { Some 1 }

‎tests/FSharpPlusFable.Tests/FSharpTests/General/Traversable.fs

+8
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ let traversable = testList "Traversable" [
9292
#endif
9393

9494
#if !FABLE_COMPILER || FABLE_COMPILER_3
95+
testList "traverse_Order" [
96+
testCase "nelist" (fun () ->
97+
SideEffects.reset()
98+
let mapper v = SideEffects.add <| sprintf "mapping %d" v
99+
let _ = traverse (Option.map mapper) [Some 1; Some 2]
100+
SideEffects.are ["mapping 1"; "mapping 2"]
101+
)]
102+
95103
testList "traversableForNonPrimitive" [
96104
testCase "nelist" (fun () ->
97105
let nel = nelist { Some 1 }

0 commit comments

Comments
 (0)