Javascript 重构对FP样式有副作用的简单算法-更新任务状态
我们有一个基本算法,它是以命令式风格编写的:Javascript 重构对FP样式有副作用的简单算法-更新任务状态,javascript,functional-programming,ramda.js,Javascript,Functional Programming,Ramda.js,我们有一个基本算法,它是以命令式风格编写的: const db = new DB() const markAsCompleted = ( taskId ) => { // Mark the task as completed db.markTaskAsCompleted( taskId ) // Update parent status const parentId = db.getTaskParentId( taskId ) if ( par
const db = new DB()
const markAsCompleted = ( taskId ) => {
// Mark the task as completed
db.markTaskAsCompleted( taskId )
// Update parent status
const parentId = db.getTaskParentId( taskId )
if ( parentId ) {
// Get parent's incomplete children
const isIncomplete = ( task ) => task.status != 'completed'
const parentChildren = db.getTaskChildren( parentId )
const incompleteTasks = parentChildren.filter( isIncomplete )
// If all children have completed, mark the parent as completed
if ( incompleteTasks.length === 0 ) {
db.markTaskAsCompleted( taskId ) // Simple case - no recursion
// markAsCompleted( parentId ) // Complex case - with recursion
}
}
}
db操作都涉及副作用(显然)
如何将其转换为函数式编程风格?也就是说,一种基于函数组合的无点风格,同时使用IO
monad并让客户端“触发”副作用。在这方面:
优选地,该溶液将使用或
还应注意以下两种情况:
- 简单,无递归(未注释)
- 带递归的复数(注释)
// replace return values of these functions with your actual db lookups
const db = {
getTaskChildren: (taskId) => IO.of([]),
getTaskParentId: (taskId) => IO.of('123'),
markTaskAsCompleted: (taskId) => IO.of(1),
};
const checkParent = (parentId) =>
db.getTaskChildren(parentId)
.map((children) =>
children.filter(({ status }) => status !== 'completed'))
.chain((incomplete) =>
incomplete.length === 0
? db.markTaskAsCompleted(parentId)
: IO.of(null)); // do nothing
const markAsCompleted = (taskId) =>
db.markTaskAsCompleted(taskId)
.chain(() => db.getTaskParentId(taskId))
.chain(checkParent);
markAsCompleted('abc').run();
如果io交换为异步,则流不应更改 通常db查找是异步的,因此使用异步adt而不是io adt,但是当您要求io时 在数据库周围创建一个包装器,该包装器可以返回计算的ios,然后链接:
// replace return values of these functions with your actual db lookups
const db = {
getTaskChildren: (taskId) => IO.of([]),
getTaskParentId: (taskId) => IO.of('123'),
markTaskAsCompleted: (taskId) => IO.of(1),
};
const checkParent = (parentId) =>
db.getTaskChildren(parentId)
.map((children) =>
children.filter(({ status }) => status !== 'completed'))
.chain((incomplete) =>
incomplete.length === 0
? db.markTaskAsCompleted(parentId)
: IO.of(null)); // do nothing
const markAsCompleted = (taskId) =>
db.markTaskAsCompleted(taskId)
.chain(() => db.getTaskParentId(taskId))
.chain(checkParent);
markAsCompleted('abc').run();
如果io交换为异步,则流不应更改 确保使用if(children.every(isCompleted))
不要使用可怕的筛选器+长度解决方案确保使用if(children.every(isCompleted))
不要使用可怕的筛选器+长度解决方案