【发布时间】:2020-12-21 20:59:14
【问题描述】:
第一次使用 fp-ts 库进入 typescript 函数式编程的世界。
我在这里有一个埃及人会引以为豪的“末日金字塔”,我的方法显然做错了什么。我应该采取什么方法来以一种不那么强制性的方式解决我的嵌套数据获取问题?
金字塔
export const getProgramWithAllElements = (programId: FirestoreDocumentId): TE.TaskEither<FirestoreError, Program> =>
pipe(
getProgram(programId),
TE.chain((program) =>
pipe(
getCollCollectionsFromPath(program.id),
TE.chain((collections) =>
pipe(
collections,
A.map((collection) =>
pipe(
getWeekCollectionsFromPath(program.id)(collection.id),
TE.chain((weeks) =>
pipe(
weeks,
A.map((week) =>
pipe(
getDayCollectionsFromPath(program.id)(collection.id)(week.id),
TE.chain((days) =>
pipe(
days,
A.map((day) =>
pipe(
getExerciseCollectionsFromPath(program.id)(collection.id)(week.id)(day.id),
TE.map(
(exercises) =>
({
...day,
exercises: exercises,
} as Day)
)
)
),
A.sequence(TE.taskEither)
)
),
TE.map(
(days) =>
({
...week,
days: days,
} as Week)
)
)
),
A.sequence(TE.taskEither)
)
),
TE.map(
(weeks) =>
({
...collection,
weeks: weeks,
} as Collection)
)
)
),
A.sequence(TE.taskEither)
)
),
TE.map(
(collections) =>
({
...program,
collections: collections,
} as Program)
)
)
)
);
sn-p中使用的函数
declare const getProgram: (programId: FirestoreDocumentId) => TE.TaskEither<FirestoreError, Program>;
declare const getCollCollectionsFromPath: (
programId: FirestoreDocumentId
) => TE.TaskEither<FirestoreError, Collection[]>;
declare const getWeekCollectionsFromPath: (
programId: FirestoreDocumentId
) => (collectionId: FirestoreDocumentId) => TE.TaskEither<FirestoreError, Week[]>;
declare const getDayCollectionsFromPath: (programId: FirestoreDocumentId) => (collectionId: FirestoreDocumentId) => (
weekId: FirestoreDocumentId
) => TE.TaskEither<FirestoreError, Day[]>;
declare const getExerciseCollectionsFromPath: (programId: FirestoreDocumentId) => (collectionId: FirestoreDocumentId) => (
weekId: FirestoreDocumentId
) => (dayId: FirestoreDocumentId) => TE.TaskEither<FirestoreError, Exercise[]>;
简化数据模型
export interface Program {
id: string;
// Other Fields
collections?: Collection[];
}
export interface Collection {
id: string;
// Other Fields
weeks?: Week[];
}
export interface Week {
id: string;
// Other Fields
days?: Day[];
}
export interface Day {
id: string;
// Other Fields
exercises: ProgramExercise[];
}
export interface ProgramExercise {
id: string;
// Other Fields
}
【问题讨论】:
-
如果你想要更函数化的编程风格,不要这样使用
pipe。 -
getExerciseCollectionsFromPath(program.id)(collection.id)(week.id)(day.id)- 该 API 有问题。为什么不day.getExercises()(或getExercises(day))? -
感谢@Bergi 的回复我了解管道的使用是错误的,并且必须基于对实用程序的一些错误理解或有限的知识,在我的情况下有什么替代方案?
getExerciseCollectionsFromPath(program.id)(collection.id)(week.id)(day.id)是一个调用 Firebase Firestore NoSQL 数据库的函数。我不知道您使用 Firestore 的经验,但存储练习的子集合不知道它的父日集合。因此,您需要指定访问它的整个路径,例如(program.id)(collection.id)(week.id)(day.id) -
关于
pipe,而不是pipe(val, g, f),只写f(g(val))。或者代替val => pipe(val, g, f),只写compose(f, g)。似乎这已经可以节省金字塔的一些缩进级别。 -
关于集合的访问,如果你在day接口中包含了星期,星期中的集合等,你只需要传递包含所有必要标识符的day对象。
标签: typescript functional-programming fp-ts