diff --git a/CHANGELOG.md b/CHANGELOG.md index dd6fbef48c..a1cf44730f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added support for configuring pins and width for sdmmc on ESP32 - Added support for map comprehensions - Added USB CDC port drivers for ESP32, RP2, and STM32 platforms +- Added `lists:mapfoldr/3` ### Changed - Updated network type db() to dbm() to reflect the actual representation of the type diff --git a/libs/estdlib/src/lists.erl b/libs/estdlib/src/lists.erl index ff2a612db4..6688d02c59 100644 --- a/libs/estdlib/src/lists.erl +++ b/libs/estdlib/src/lists.erl @@ -50,6 +50,7 @@ foldl/3, foldr/3, mapfoldl/3, + mapfoldr/3, all/2, any/2, flatten/1, @@ -412,6 +413,22 @@ mapfoldl0(Fun, {List1, Acc0}, [H | T]) -> {B, Acc1} = Fun(H, Acc0), mapfoldl0(Fun, {[B | List1], Acc1}, T). +%%----------------------------------------------------------------------------- +%% @param Fun the function to apply +%% @param Acc0 the initial accumulator +%% @param List the list over which to fold +%% @returns the result of mapping and folding Fun over List, from right to left +%% @doc Combine `map/2' and `foldr/3' in one pass. +%% @end +%%----------------------------------------------------------------------------- +-spec mapfoldr(fun((A, Acc) -> {B, Acc}), Acc, [A]) -> {[B], Acc}. +mapfoldr(_Fun, Acc0, []) -> + {[], Acc0}; +mapfoldr(Fun, Acc0, [H | T]) -> + {Bs, Acc1} = mapfoldr(Fun, Acc0, T), + {B, Acc2} = Fun(H, Acc1), + {[B | Bs], Acc2}. + %%----------------------------------------------------------------------------- %% @equiv foldl(Fun, Acc0, reverse(List)) %% @doc Fold over a list of terms, from right to left, applying Fun(E, Accum) diff --git a/tests/libs/estdlib/test_lists.erl b/tests/libs/estdlib/test_lists.erl index 7a0a76b7bc..5485115786 100644 --- a/tests/libs/estdlib/test_lists.erl +++ b/tests/libs/estdlib/test_lists.erl @@ -477,6 +477,17 @@ test_mapfoldl() -> lists:mapfoldl(fun(X, A) -> {X * A, A + 1} end, 1, [1, 2, 3]) ), ?ASSERT_ERROR(lists:mapfoldl(fun(X, A) -> {X * A, A + 1} end, 1, foo), function_clause), + ok = test_mapfoldr(), + ok. + +test_mapfoldr() -> + ?ASSERT_MATCH({[], 1}, lists:mapfoldr(fun(X, A) -> {X * A, A + 1} end, 1, [])), + %% Right-to-left: the accumulator visits 3, then 2, then 1. + ?ASSERT_MATCH( + {[3, 4, 3], 4}, + lists:mapfoldr(fun(X, A) -> {X * A, A + 1} end, 1, [1, 2, 3]) + ), + ?ASSERT_ERROR(lists:mapfoldr(fun(X, A) -> {X * A, A + 1} end, 1, foo), function_clause), ok. test_append() ->