【问题标题】:Remove Options from array of items in fp-ts从 fp-ts 中的项目数组中删除选项
【发布时间】:2021-03-11 00:20:19
【问题描述】:

假设我有以下类型:

type ValidatedInput = Readonly<{
  id: string
}>

type GetStructures = (id: string) => TaskEither<ServiceError, ReadonlyArray<SomeStructure>>

type GetOtherStructures = (ids: ReadonlyArray<string>) => TaskEither<ServiceError, ReadonlyArray<SomeOtherStructure>>

type LookupThings = (initialInput: ReadonlyArray<SomeStructure>, additionalInput: ReadonlyArray<SomeOtherStructure>) => TaskEither<ServiceError, ReadonlyArray<Option<ResponseType>>>

export type Deps = Readonly<{
  getStructures: GetStructures
  getOtherStructures: GetOtherStructures
  lookupThings: LookupThings
}>

export type Ctx<T> = ReaderTaskEither<Deps, Error, T>

还有以下错误处理助手:

type Code = 'INVALID_ENTITY' | 'INVALID_API_KEY'
export const fromCode = (code: Code): Error => ({
  tag: 'validation',
  code
})

然后我像这样创建一个函数:

const constructFullData = (input: ValidatedInput): Ctx<ReadonlyArray<Option<ResponseType>>> => (
  (deps: Deps): TE.TaskEither<Error, ReadonlyArray<Option<ResponseType>>> => (
    pipe(
      deps.getStructures(input.id),
      TE.map((structs) => pipe(
        deps.getOtherStructures([structs[0].higherOrderId]),
        TE.chain(otherStructs => pipe(
          deps.lookupThings(structs, otherStructs),
          TE.chain(results => {
            if (results.filter(isNone).length !== results.length) {
              return TE.left(fromCode('INVALID_ENTITY')) // I'm not sure what a better way to filter this is. Ideally the return type of this  function wouldn't have an Option in it
            } else {
              return TE.right(results)
            }
          })
        ))
      )),
      TE.flatten
    )
  )
)

这一切都编译得很好,但我真正想要的是返回一个没有过滤掉的数组,如果没有则引发相应的错误!

天真的做法是将Right path的返回改为:

return TE.right(results.map(u => u.value))

但这并不能编译,抛出如下错误:

Property 'value' does not exist on type 'None'.
64               return TE.right(usagesWithDrones.map(u => u.value))

如何应用这种过滤?

【问题讨论】:

  • 如果我错了,请纠正我,但是“我真正想要的是返回一个没有过滤掉的数组,如果没有则引发适当的错误”意味着你想要返回原始数组(如果它们都是 Some),或者如果只有一个 None,则返回错误。为此,fp-ts/Arraysequence:假设 x 是 Option&lt;number&gt;[],那么 Array.sequence(option)(x) 将产生 Some&lt;number[]&gt; 如果它们都是 Some 或 None 如果即使单个是 None 。

标签: typescript functional-programming fp-ts


【解决方案1】:

如果将选项列表折叠成一个呢?比如:

import * as TE from "fp-ts/TaskEither";
import * as ROA from "fp-ts/ReadonlyArray";
import * as T from "fp-ts/Task";
import * as E from "fp-ts/Either";
import * as O from "fp-ts/Option";
import { pipe } from "fp-ts/pipeable";
import { constant, flow, Lazy } from "fp-ts/lib/function";

const value = TE.right<"ThisErrorDoesntExist", readonly O.Option<number>[]>(
  ROA.of(O.some(42))
);

const arrayOfNumbersMonoid = ROA.getMonoid<number>();

type Result = E.Either<"FoundNoneInList", readonly number[]>;

const rightEmptyListOfNumbers: Result = E.right([]);

const leftFoundNoneInList: Lazy<Result> = constant(E.left("FoundNoneInList"));

const reducer = (acc: typeof rightEmptyListOfNumbers, next: O.Option<number>) =>
  pipe(
    acc,
    E.chain((numbers) =>
      pipe(
        next,
        O.fold(
          leftFoundNoneInList,
          flow(ROA.of, (n) => arrayOfNumbersMonoid.concat(numbers, n), E.right)
        )
      )
    )
  );

const result = pipe(
  value,
  T.map(E.chainW(ROA.reduce(rightEmptyListOfNumbers, reducer)))
);

【讨论】:

    【解决方案2】:

    从数组中删除选项的最简单方法是使用 compact 函数(参见下面的简单示例)。 compact 函数存在于大多数 fp-ts 库中。

    import { Option, some, none } from "fp-ts/lib/Option"
    import { compact } from "fp-ts/lib/Array"
    
    const initialArray = [1, 2, 3, 4, 5, 6, 7]
    
    const arrayWithOptions: Option<number>[] = initialArray.map((el) => {
      if (el % 2 === 0) return some(el)
      else return none
    })
    
    const finalArray: number[] = compact(arrayWithOptions)
    
    console.log(finalArray)
    

    控制台日志将打印 [2,4,6]。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-24
      • 2021-10-19
      • 2021-10-03
      • 1970-01-01
      • 2014-09-21
      • 1970-01-01
      • 2013-06-08
      • 2020-07-01
      相关资源
      最近更新 更多