Task, Lift и сложные монады в FP-TS - PullRequest
1 голос
/ 19 мая 2019

У меня есть следующий код:

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 будет применяться к параметрам buildPerson, как liftA2 делает

3) Есть ли лучший способ для составления функций?

1 Ответ

0 голосов
/ 11 июля 2019

Это осложнение вызвано необходимостью переходить от одного к другому и к задаче, и между этими двумя типами нет естественного преобразования.Почему бы не использовать существующий тип taksEither?У fp ts очень плохие документы, поэтому я переписал твой код, используя другую библиотеку (от 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 и возвращает будущее списка, это поведение по существу конкатное и должно существовать в задании fp-ts, потому что его необходимо реализовать на монадах

Далее, если вы перепроектировали репокласс и его методы возвращают taskeithers, вы еще больше упростите свой код.

...