【问题标题】:How to pipe ap calls after using getApplicativeValidation on an Either in fp-ts?在 fp-ts 中的 Either 上使用 getApplicativeValidation 后如何通过管道传输 ap 调用?
【发布时间】:2021-08-28 03:16:47
【问题描述】:

昨天我和几个同事试图在 fp-ts 中获得一个用于应用验证的玩具示例。我们终于让它通过手动将每个中间步骤存储在一个变量中并调用下一步来工作。但是使用 fp-ts 的 pipe 函数会更加优雅。直接使用 Either 可以工作,但不会将多个 Left 值合并为一个(例如,将带有字符串错误的数组连接起来)。 但是对于 pipe(),ap() 调用需要两个参数,但只能得到一个。我们如何在这里正确使用管道:

import * as E from "fp-ts/lib/Either";
import * as RA from "fp-ts/lib/ReadonlyArray";
import { pipe } from "fp-ts/lib/function";

export class CreditCard {
    constructor(
        public readonly number: string,
        public readonly expiry: string,
        public readonly cvv: string
    ) { }
}

export const validate = (
    card: CreditCard
): E.Either<ReadonlyArray<string>, CreditCard> => {
    const createCreditCard = (a: string) => (b: string) => (c: string) =>
        new CreditCard(a, b, c);

    const v1 = (s: string): E.Either<ReadonlyArray<string>, string> => {
        return s !== "invalid" ? E.right(s) : E.left(RA.of("invalid number"));
    };

    const v2 = (s: string): E.Either<ReadonlyArray<string>, string> => {
        return s !== "invalid" ? E.right(s) : E.left(RA.of("invalid expiry"));
    };

    const v3 = (s: string): E.Either<ReadonlyArray<string>, string> => {
        return s !== "invalid" ? E.right(s) : E.left(RA.of("invalid cvv"));
    };

    const V = E.getApplicativeValidation((RA.getSemigroup<string>()));

    // this does not work, because V.ap wants 2 arguments but only has 1?
    // const fromPipe = pipe(
    //     V.of(createCreditCard),
    //     V.ap(v1(card.number)),
    //     V.ap(v2(card.expiry)),
    //     V.ap(v3(card.cvv))
    // );
    // return fromPipe;

    // this works, but is ugly
    const liftedFunction = V.of(createCreditCard);
    const afterFirstValidation = V.ap(liftedFunction, v1(card.number));
    const afterSecondValidation = V.ap(afterFirstValidation, v2(card.expiry));
    const afterThirdValidation = V.ap(afterSecondValidation, v3(card.cvv));

    return afterThirdValidation;
};

【问题讨论】:

    标签: typescript applicative fp-ts


    【解决方案1】:

    Either.getApplicativeValidation 返回一个Applicative2C 的实例,它具有类方法的不可管道版本。目前,您获得使用组合器(如getApplicativeValidation)计算的可管道版本的实例的方式是将实例从pipeable.ts 模块传递给pipeable 组合器。

    所以把你的代码改成这样:

    const validation = E.getApplicativeValidation(RA.getSemigroup<string>())
    const V = pipeable(validation)
    
    const fromPipe = pipe(
      validation.of(createCreditCard),
      V.ap(v1(card.number)),
      V.ap(v2(card.expiry)),
      V.ap(v3(card.cvv))
    )
    

    您应该会发现它可以按您的意愿工作。

    但是,我相信fp-ts v3.x.x 中,类型类接口默认会更改为全部可管道,因此对pipeable 的需求将消失。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-01
      • 2020-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-29
      相关资源
      最近更新 更多