2

I have defined an operator flatReduce() which is to reduce() what flatMap() is to map():

public class FlatReduce {
    public static <V, W> Mono<V> flatReduce(Mono<V> initial, Iterable<W> items, BiFunction<V, W, Mono<V>> accumulator) {
        for (W item : items) {
            initial = initial.flatMap(v -> accumulator.apply(v, item));
        }
        return initial;
    }

    public static void main(String[] args) {
        flatReduce(Mono.just(1), IntStream.range(0, 4000).mapToObj(it -> it).collect(toList()), (a, b) -> Mono.just(a + b)).block();
    }
}

This yields deeply nested flatMaps and I have observed stack overflows. Is there any way to work around this (maybe turning this into continuation style)?

Thanks.

Thipor Kong
  • 597
  • 3
  • 8
  • This sounds super interesting, but could you please explain in more detail and with an example, what flatReduce does? *"to `reduce()` what `flatMap()` is to `map()`"* evokes things in my mind, but none of those things sound very practical, nor sound like they could be implemented efficiently. – Stef Sep 05 '21 at 13:09

1 Answers1

1

Found a workaround by converting the Mono to CompletableFuture.

    @Test
    public void runTest() {
        System.out.println(flatReduce(Mono.just(1), IntStream.range(1, 500000).mapToObj(it -> it).collect(toList()), (a, b) -> Mono.just(a + 1)).block());
    }

    private static <V, W> Mono<V> flatReduce(Mono<V> initial, List<W> items, BiFunction<V, W, Mono<V>> accumulator) {
        return Mono.fromCompletionStage(flatReduceWithFuture(initial.toFuture(), items, (v, w) -> accumulator.apply(v, w).toFuture()));
    }

    private static <V, W> CompletableFuture<V> flatReduceWithFuture(CompletableFuture<V> initial, List<W> items, BiFunction<V, W, CompletableFuture<V>> accumulator) {
        for (W item : items) {
            initial = initial.thenCompose(x -> accumulator.apply(x, item));
        }
        return initial;
    }
Thipor Kong
  • 597
  • 3
  • 8