Как перейти от ReaderEither[] к ReaderEither в fp-ts?

#typescript #functional-programming #fp-ts

#typescript #функциональное программирование #fp-ts

Вопрос:

В fp-ts, как мне перейти от ReaderEither<R, E, A>[] к ReaderEither<R, E[], A[]> ? По сути, я хочу преобразовать массив ReaderEither экземпляров в один ReaderEither экземпляр.

Я пытался найти ответ, но не очень повезло. Я новичок в функциональном программировании и fp-ts, поэтому я все еще пытаюсь разобраться во всех концепциях и применить их на практике. Я ценю вашу помощь.

Комментарии:

1. Я считаю, что проходимость может быть ключом. Я нашел несколько примеров его использования с Option и Either , но у меня возникли проблемы с тем, чтобы заставить его работать с ReaderEither . gcanti.github.io/fp-ts/modules/Traversable.ts.html

2. Вы можете получить a ReaderEither<R, E, A[]> из a ReaderEither<R, E, A>[] с sequenceT помощью, но я не уверен, как накапливать ошибки.

3. Вы уверены, что хотите a ReaderEither<R, E[], A[]> ? Это то же самое, что и a Reader<R, Either<E[], A[]>> ; вы хотите Reader<R, Either<E, A>[]> вместо a ?

4. Да, я надеюсь собрать результаты в одном Either , а не иметь несколько Either

5. Как вы хотите, чтобы это работало? Что, если некоторые из ReaderEither s возвращают a Left , а некоторые возвращают a Right ? Вы хотите, чтобы финал Either зависел от первого ReaderEither (например, если первый ReaderEither возвращает a Left , верните a Left<E[]> , накапливая другие Left s и отбрасывая Right s)? А что, если ReaderEither<R, E, A>[] пусто?

Ответ №1:

Попробуйте это:

 import * as A from 'fp-ts/Array'
import {left, right} from 'fp-ts/Either'
import * as R from 'fp-ts/Reader'
import {flow} from 'fp-ts/function'
import type {ReaderEither} from 'fp-ts/ReaderEither'

const sequenceRE: <R, E, A>(
  fs: ReaderEither<R, E, A>[]
) => ReaderEither<R, E[], A[]> = flow(
  // ReaderEither<R, E, A>[] -> Reader<R, Either<E, A>[]>
  A.sequence(R.reader),
  // Maps the reader: Reader<R, Either<E, A>[]> -> ReaderEither<R, E[], A[]>
  R.map(flow(
    // Either<E, A>[] -> Separated<E[], A[]>
    A.separate,
    // Separated<E[], A[]> -> Either<E[], A[]>
    s => s.left.length ? left(s.left) : right(s.right)
  ))
)

// Right [4, 6]
sequenceRE([r => right(r * 2), r => right(r * 3)])(2)
// Left ['foo', 'bar']
sequenceRE([r => right(r * 2), r => left('foo'), r => left('bar')])(2)
// Right []
sequenceRE([])(2)
  

Код делает это:

  • sequence s (из Traversable ) ReaderEither<R, E, A>[] в Reader<R, Either<E, A>[]>

  • separate s (из Compactable ) Either<E, A>[] из читателя в {left: E[], right: A[]}

     interface Separated<A, B> {
      readonly left: A
      readonly right: B
    }
    
    // For Array:
    declare const separate: <A, B>(fa: Either<A, B>[]) => Separated<A[], B[]>
      
  • Если есть какие-либо Left s, возвращает a Left со Left значениями, а в противном случае возвращает a Right со Right значениями.

Комментарии:

1. Это сработало прекрасно. Большое вам спасибо. Я уже несколько дней «раскручиваю шины» над этим.