将不同结果类型的多个“Try”实例组合为应用程序

Combining multiple `Try` instances of different result types as applicatives

是否有一个 api 用于在 Vavr 中组合 Try 个实例,类似于 Scalaz 应用运算符 |@| 的工作方式?

具体来说,如果我有两个以上的 Try 实例,例如 Try<X>Try<Y>Try<Z>,我想将这些实例组合成一个使用 3-arg 函数的应用时尚。

我正在寻找类似于以下内容的函数签名:

static <X, Y, Z, R> Try<R> combine(Try<X> x, Try<Y> y, Try<Z> z, Function3<X,Y,Z,R> func

据我所知,它不直接支持该用法。但是,您可以使用 flatMap 实现它:

static <X, Y, Z, R> Try<R> combine(Try<X> tx, Try<Y> ty, Try<Z> tz, Function3<X,Y,Z,R> func) {
    return tx.flatMap(x -> ty.flatMap(y -> tz.map(z -> func.apply(x, y, z))));
}

如果每个 Try 值包含相同的类型,那么您可以使用 sequence 操作:

public static void main(String[] args) {
    List<Try<String>> lt = List.of(Try.success("A"), Try.success("B"), Try.success("C"));
    Try<List<String>> tl = sequence(lt);
    System.out.println(tl);
}

static <T> Try<List<T>> sequence(List<Try<T>> lt) {
    return lt.foldRight(
        Try.success(List.empty()),
        (tt, tl) -> tt.flatMap(t -> tl.flatMap(l -> Try.success(l.prepend(t))))
    );
}

如果比较输入和输出类型,您会发现这实质上交换了 TryList 容器的位置。这对于 monad 来说是相当惯用的,尽管通常您会使用应用映射操作而不是 flatMap 来实现它。

或者,使用 Validation,它被设计用于应用风格(通过 Validation.combine)。

正如您提到的,vavr 上没有类似的方法,但是您可以采取一些解决方法:

使用元组:

    Try.success(authorizationHeader)
  .map(mapper::hcpFrom)
  .map(hcp -> Tuple.of(hcp, mapper.toSaveNoteRequest(noteId, patientId, requestBody, clock)))
  .map(t2 -> saveNoteUseCase.execute(t2._1(), t2._2()))
  .map(mapper::toHcpNoteResponse)
  .map(response -> accepted().body(response))
  .get();

使用 For 产生:

For(Try.success(authorizationHeader).map(mapper::hcpFrom), Try.success(mapper.toSaveNoteRequest(noteId, patientId, requestBody, clock)))
  .yield(saveNoteUseCase::execute)
  .map(mapper::toHcpNoteResponse)
  .map(response -> accepted().body(response))
  .get();

在 flatMap 中使用代码:

Try.success(authorizationHeader)
  .map(mapper::hcpFrom)
  .flatMap(hcp-> Try.of(() -> mapper.toSaveNoteRequest(noteId, patientId, requestBody, clock)).map(saveNoteRequest -> saveNoteUseCase.execute(hcp, saveNoteRequest)))
  .map(mapper::toHcpNoteResponse)
  .map(response -> accepted().body(response))
  .get();

最后使用 futures(如 api,但不推荐)

Try.success(authorizationHeader).map(mapper::hcpFrom).toCompletableFuture()
  .thenCombine(Try.success(mapper.toSaveNoteRequest(noteId, patientId, requestBody, clock)).toCompletableFuture(), saveNoteUseCase::execute)
  .thenApply(mapper::toHcpNoteResponse)
  .thenApply(response -> accepted().body(response))
  .join();

亲切的问候。