Skip to content

Commit

Permalink
stdlib: add Array.fold_left_map
Browse files Browse the repository at this point in the history
  • Loading branch information
craigfe committed Oct 7, 2020
1 parent 0e6bc29 commit 73f9685
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ Working version
(David Allsopp, review by Nicolás Ojeda Bär, Sébastien Hinderer and
Xavier Leroy)

- #TODO: Add Array.fold_left_map.
(Craig Ferguson, review by TODO)

### Other libraries:

* #9206, #9419: update documentation of the threads library;
Expand Down
14 changes: 14 additions & 0 deletions stdlib/array.ml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,20 @@ let fold_left f x a =
done;
!r

let fold_left_map f acc input_array =
let len = length input_array in
if len = 0 then (acc, [||]) else begin
let acc, elt = f acc (unsafe_get input_array 0) in
let output_array = create len elt in
let acc = ref acc in
for i = 1 to len - 1 do
let acc', elt = f !acc (unsafe_get input_array i) in
acc := acc';
unsafe_set output_array i elt;
done;
!acc, output_array
end

let fold_right f a x =
let r = ref x in
for i = length a - 1 downto 0 do
Expand Down
5 changes: 5 additions & 0 deletions stdlib/array.mli
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b array -> 'a
[f (... (f (f init a.(0)) a.(1)) ...) a.(n-1)],
where [n] is the length of the array [a]. *)

val fold_left_map : ('a -> 'b -> 'a * 'c) -> 'a -> 'b array -> 'a * 'c array
(** [fold_left_map] is a combination of {!fold_left} and {!map} that threads an
accumulator through calls to [f].
@since 4.12.0 *)

val fold_right : ('b -> 'a -> 'a) -> 'b array -> 'a -> 'a
(** [fold_right f a init] computes
[f a.(0) (f a.(1) ( ... (f a.(n-1) init) ...))],
Expand Down
5 changes: 5 additions & 0 deletions stdlib/arrayLabels.mli
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ val fold_left : f:('a -> 'b -> 'a) -> init:'a -> 'b array -> 'a
[f (... (f (f init a.(0)) a.(1)) ...) a.(n-1)],
where [n] is the length of the array [a]. *)

val fold_left_map : f:('a -> 'b -> 'a * 'c) -> init:'a -> 'b array -> 'a * 'c array
(** [fold_left_map] is a combination of {!fold_left} and {!map} that threads an
accumulator through calls to [f].
@since 4.12.0 *)

val fold_right : f:('b -> 'a -> 'a) -> 'b array -> init:'a -> 'a
(** [fold_right ~f a ~init] computes
[f a.(0) (f a.(1) ( ... (f a.(n-1) init) ...))],
Expand Down
15 changes: 15 additions & 0 deletions testsuite/tests/lib-array/test_array.ml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,18 @@ val a : float array = [|0.; 0.; 0.; 0.; 0.; 0.; 0.; 0.|]
- : unit = ()
- : float array = [|0.; 0.; 42.; 42.; 42.; 0.; 0.; 0.|]
|}]

let a = Array.init 8 succ;;
let _ = Array.fold_left_map (fun a b -> a + b, string_of_int b) 0 a;;
a (* [a] is unchanged *);;
[%%expect {|
val a : int array = [|1; 2; 3; 4; 5; 6; 7; 8|]
- : int * string array = (36, [|"1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"|])
- : int array = [|1; 2; 3; 4; 5; 6; 7; 8|]
|}]

let (_ : (_ * unit array)) =
Array.fold_left_map (fun _ _ -> assert false) 0 [||];;
[%%expect{|
- : int * unit array = (0, [||])
|}]

0 comments on commit 73f9685

Please sign in to comment.