#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[]>
из aReaderEither<R, E, A>[]
сsequenceT
помощью, но я не уверен, как накапливать ошибки.3. Вы уверены, что хотите a
ReaderEither<R, E[], A[]>
? Это то же самое, что и aReader<R, Either<E[], A[]>>
; вы хотитеReader<R, Either<E, A>[]>
вместо a ?4. Да, я надеюсь собрать результаты в одном
Either
, а не иметь несколькоEither
5. Как вы хотите, чтобы это работало? Что, если некоторые из
ReaderEither
s возвращают aLeft
, а некоторые возвращают aRight
? Вы хотите, чтобы финалEither
зависел от первогоReaderEither
(например, если первыйReaderEither
возвращает aLeft
, верните aLeft<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, возвращает aLeft
соLeft
значениями, а в противном случае возвращает aRight
соRight
значениями.
Комментарии:
1. Это сработало прекрасно. Большое вам спасибо. Я уже несколько дней «раскручиваю шины» над этим.