0

在函数式编程中使用删除 Either 数组重复项的最佳方法是什么fp-ts

这是我的尝试:

import { either as E, pipeable as P } from "fp-ts";
import { flow } from "fp-ts/lib/function";

interface IItem {
  type: "VALID" | "INVALID";
  value: string;
}

// Building some fake data
const buildItem = (value?: string): E.Either<unknown, string> =>
  value != null ? E.right(value) : E.left({ type: "INVALID", value: "" });

// We will always have an array of Either
const items = [
  buildItem("aa"),
  buildItem("ab"),
  buildItem(),
  buildItem("ac"),
  buildItem("ab"),
  buildItem("ac"),
  buildItem(),
  buildItem("aa")
];

const checkList: string[] = [];
export const program = flow(
  () => items,
  x =>
    x.reduce(
      (acc, item) =>
        P.pipe(
          item,
          E.chain(value => {
            if (checkList.indexOf(value) < 0) {
              checkList.push(value);
              return E.right({ type: "VALID", value: value } as IItem);
            }
            return E.left({ type: "INVALID", value: value } as IItem);
          }),
          v => acc.concat(v)
        ),
      [] as E.Either<unknown, IItem>[]
    )
);

游乐场链接

4

1 回答 1

2

通常,在 中fp-ts,您可以Array<A>使用uniqfrom删除重复项fp-ts/lib/Array。给定 anEq<A>和 anArray<A>它将返回一个Array<A>所有As 都是唯一的。

在您的情况下,您似乎想要对Array<Either<IItem, IItem>>. 这意味着,为了使用uniq,您将需要一个Eq<Either<IItem, IItem>>. 你得到的方法是使用getEqfrom fp-ts/lib/EitherEq它要求您为您参数化的每种类型提供一个实例Either,一个用于左侧情况,另一个用于右侧情况。所以 for Either<E, R>,getEq会取 anEq<E>和 anEq<R>并给你一个Eq<Either<E, R>>. 在您的情况下,E并且R是相同的(即IItem),因此您只需使用相同的Eq<IItem>实例两次。

您想要的实例很可能Eq<IItem>如下所示:

// IItem.ts |
//-----------
import { Eq, contramap, getStructEq, eqString } from 'fp-ts/lib/Eq'

export interface IItem {
  type: "VALID" | "INVALID";
  value: string;
}

export const eqIItem: Eq<IItem> = getStructEq({
  type: contramap((t: "VALID" | "INVALID"): string => t)(eqString),
  value: eqString
})

一旦你有了它,你就可以像这样对你Array<Either<IItem, IItem>>的重复数据删除uniq

// elsewhere.ts |
//---------------
import { array, either } from 'fp-ts'
import { Either } from 'fp-ts/lib/Either'
import { IItem, eqIItem } from './IItem.ts'

const items: Array<Either<IItem, IItem>> = []

const uniqItems = uniq(either.getEq(eqIItem, eqIItem))(items)

然后,uniqItems常数将是一个Array<Either<IItem, IItem>>,其中没有两个Either<IItem, IItem>“相等”,如 所定义Eq<Either<IItem, IItem>>

于 2020-04-24T20:35:30.387 回答