【问题标题】:Task, Lift and complex monads in FP-TSFP-TS 中的任务、提升和复杂单子
【发布时间】:2019-05-18 21:28:51
【问题描述】:

我有以下代码:

import { Task, task } from "fp-ts/lib/Task"
import { Either, left, right } from "fp-ts/lib/Either"
import { curry } from "fp-ts/lib/function"
import { liftA2 } from "fp-ts/lib/Apply"
import { Repo } from "./repo"

const buildPerson = curry((name: string, age: number): Either<Error, any> => {
    if (name !== undefined && age !== undefined) {
        return right({ name, age })
    } else {
        return left(Error("Missing parameter"))
    }
})

const validatePerson = (person: any): Either<Error, any> => {
    if ( person.age < 18) {
        return left(Error("Too Young")) 
    } else {
        return right(person)
    }
}

const getNameFromRepo = (repo: Repo): Task<string> => {
    return new Task(
        () => repo.getName()
    )
}

const getAgeFromRepo = (repo: Repo): Task<number> => {
    return new Task(
        () => repo.getAge()
    )
}

const savePerson = curry((person:any, repo: Repo): Task<void> => {
    return new Task(
        () => {
            console.log(person)
            return repo.setPerson(person)
        }
    )
})

const hello = async () => {
    const repo = new Repo()

    await liftA2(task)(buildPerson)(getNameFromRepo(repo))(getAgeFromRepo(repo))
    .map(
        (e) => e.chain(
            (p) => validatePerson(p)
        )
    )
    .map(
        (e) => e.fold(
            (l) => console.log(l),
            (r) => savePerson(r)
        )
    )
    .run()
}

hello()

1) savePerson 函数没有运行,但是返回类型是 Promise

2) Fp-Ts 库表明不推荐使用 liftA2 类型,我应该改用 sequenceT。但是,从签名中不清楚 sequenceT 如何像 liftA2 那样应用于 buildPerson 的参数

3) 有没有更好的方法来组合函数?

【问题讨论】:

  • 我喜欢这种类型的编码,但我还没有真正找到一种方法来将它用于一般消费。这是练习编码还是实际使用?
  • 您的(e) =&gt; e.fold(l =&gt; console.log(l), r =&gt; savePerson(r)) 函数确实返回undefinedTask。该任务永远不会运行,因为您将该函数用作map 的回调 - 如果您想链接任务,您需要使用chain。 (并将console.log 调用也包含在一个任务中)。

标签: typescript functional-programming fp-ts


【解决方案1】:

这种复杂性是由于需要在任务和任务之间切换,并且两种类型之间没有自然转换。为什么不使用现有的 taksEither 类型? fp ts 的文档很差,所以我使用不同的库的 taskeither(来自 Fluture js)重写了您的代码

相反,这是使用fluturejs的外观(本质上是任务+两者之一)

import * as Future from 'fluture';

const buildPerson = (name, age) =>
    name !== undefined && age !== undefined
        ? Future.of({ name, age })
        : Future.reject(Error("Missing parameter"));

const validatePerson = ({ name, age }) =>
    age < 18
        ? Future.reject(Error("Too Young"))
        : Future.of({ name, age });

const getNameFromRepo = (repo: Repo) => {
    return Future.Future((reject, resolve) =>
        resolve(repo.getName()));
}

const getAgeFromRepo = (repo: Repo) => {
    return Future.Future((reject, resolve) =>
        resolve(repo.getAge()));
}

const savePerson = (repo: Repo) => (person) => {
    return Future.Future((reject, resolve) =>
        resolve(repo.setPerson(person)));
}
const hello = (repo: Repo) =>
    Future.parallel(1, [
        getNameFromRepo(repo),
        getAgeFromRepo(repo),
    ])
        .chain(([name, age]) => buildPerson(name, age))
        .chain(validatePerson)
        .chain(savePerson(repo))
        .fork(
            (err) => console.warn('err', err),
            () => console.log('it worked!'),
        );

hello(new Repo());

我无法扫描文档并弄清楚这些函数在 fp-ts 的实现中被称为什么,但我确信它们都存在。 Flutures 并行函数接受一个 Futures 列表并返回一个列表的未来,这种行为本质上是 concat 并且应该存在于 fp-ts 的任务中,因为它需要在 monads 上实现

此外,如果您重新设计了 repo 类并让它的方法返回 taskeithers,您将进一步简化您的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-22
    • 2020-02-21
    • 2021-12-04
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多