[Functional Programming] mapReduce over Async operations with first success prediction (fromNode, alt, mapReduce, maybeToAsync)
Let's say we are going to read some files, return the first file which pass the prediction method, this prediction method can be just check whether the file content contains more than 50 chars.
For reading the file, it has tow requirements, first we should have the right to read the file, then read file content, we can use Node.js method:
fs.access
fs.readFile
We won't directly using those methods, we are going to wrap those functions into Async functor:
const {Async, curry} = require('crocks');
const {fromNode} = Async; const access = fromNode(fs.access);
const readFile = fromNode(fs.readFile); const accessAsync = curry((mode, path) =>
access(path, mode)
.map(constant(path))); // readFileAsync :: Option -> a -> Async Error b
const readFileAsync = curry((option, path) =>
readFile(path, option));
By using 'fromNode', we are able to conver the Node's method into Async functor.
Here, we also put 'path' to the last params and apply 'curry', this is because we want to partially apply the params in the future.
Now 'accessAsync' & 'readFileAsync' both return 'Async' type, we can compose them:
const {Async, constant, composeK, curry} = require('crocks');
... // loadTextFile :: String -> Async Error String
const loadTextFile = composeK(
readTextFile,
checkRead
);
'loadTextFile' is the only method we want to be exported.
We also create a helper method to fork Async functor:
const fork = a => a.fork(
console.log.bind(null, 'rej'),
console.log.bind(null, 'res')
);
Full Code for funs.js:
const fs = require('fs');
const {Async, constant, composeK, curry} = require('crocks');
const {fromNode} = Async; const access = fromNode(fs.access);
const readFile = fromNode(fs.readFile); const accessAsync = curry((mode, path) =>
access(path, mode)
.map(constant(path))); // readFileAsync :: Option -> a -> Async Error b
const readFileAsync = curry((option, path) =>
readFile(path, option)); const checkRead = accessAsync(fs.constants.F_OK);
const readTextFile = readFileAsync('utf-8'); // loadTextFile :: String -> Async Error String
const loadTextFile = composeK(
readTextFile,
checkRead
); const fork = a => a.fork(
console.log.bind(null, 'rej'),
console.log.bind(null, 'res')
); module.exports = {
loadTextFile,
fork
}
Then let's continue to build our main.js file:
Let's say we have an array of filenames:
const data = [
'text.txt',
'text.big.txt',
'notfound.txt'
];
'text.txt' & 'text.big.txt' are existing files, and only 'text.big.txt' can pass the predicate function:
const isValid = x => x.length > ;
So with those in mind, let's define what we want to do:
1. We want to map over each filename in the 'data' array, read file content
2. For each content, we want to check against our 'isValid' method.
3. If the checking pass, it's done! output the content
4. If not pass the checking, we continue with next filename, repeat step No.1.
5. If all the filenames have gone though, no matching found, throw error.
6. If the list is empty, throw error.
7. If list is not empty but no matching file, and there is a not found filename, also throw error.
Step1-4 is a the main logic, step 5-7 is just some house keeping, throw some errors...
Step1-4 is prefect case for using 'mapReduce'
'mapReduce' here means, we first mapping over each case, then we do 'reduce' or let's say 'concat'; 'mapReduce' require a "empty" case, since our is Async functor, then the empty case will be a rejected async functor.
const {fork, loadTextFile} = require('./funs.js');
const {Async, curry, safe, mapReduce, maybeToAsync} = require('crocks'); const data = [
'text.txt',
'notfound.txt',
'text.big.txt',
]; const isValid = x => x.length > ; const concatAlt = pred =>
(acc, curr) =>
acc.alt(curr)
.chain(maybeToAsync(new Error('not good!'), safe(pred))) const flow = curry(pred => mapReduce(
loadTextFile, //map
concatAlt(pred), // reduce
Async.Rejected(new Error('list is empty')) //Seed
)); fork(flow(isValid, data));
Let's have a look 'concatAlt' in more details:
const concatAlt = pred =>
(acc, curr) =>
acc.alt(curr) // If acc async is rejected, then check curr, otherwise continue to next step 'chain' with the value of acc
.chain(maybeToAsync(new Error('not good!'), safe(pred))) // Async(Error String) --safe(pred)--> Async(Maybe(Error String)) --maybeToAsync--> Async(Async(Error String)) --chain--> Async(Error String)
'alt': works as fallback option, only has effect when 'acc' is falsy. Which means, if first two files cannot pass 'isValid' checking, but third passing, then we are still good! Also means, if the first one is passing the check, then we are not going to continue with next two files.
Here we are also using natural transform, maybeToAsync, more detail check my another post.
[Functional Programming] mapReduce over Async operations with first success prediction (fromNode, alt, mapReduce, maybeToAsync)的更多相关文章
- [Functional Programming] mapReduce over Async operations and fanout results in Pair(rejected, resolved) (fanout, flip, mapReduce)
This post is similar to previous post. The difference is in this post, we are going to see how to ha ...
- [Functional Programming] Use Task/Async for Asynchronous Actions
We refactor a standard node callback style workflow into a composed task-based workflow. Original Co ...
- [Functional Programming] Reader with Async ADT
ReaderT is a Monad Transformer that wraps a given Monad with a Reader. This allows the interface of ...
- Functional Programming without Lambda - Part 2 Lifting, Functor, Monad
Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...
- Monad (functional programming)
In functional programming, a monad is a design pattern that defines how functions, actions, inputs, ...
- JavaScript Functional Programming
JavaScript Functional Programming JavaScript 函数式编程 anonymous function https://en.wikipedia.org/wiki/ ...
- Beginning Scala study note(4) Functional Programming in Scala
1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...
- Functional Programming without Lambda - Part 1 Functional Composition
Functions in Java Prior to the introduction of Lambda Expressions feature in version 8, Java had lon ...
- a primary example for Functional programming in javascript
background In pursuit of a real-world application, let’s say we need an e-commerce web applicationfo ...
随机推荐
- wpf企业应用之带选项框的TreeView
wpf里面实现层次绑定主要使用HierarchicalDataTemplate,这里主要谈一谈带checkbox的treeview,具体效果见 wpf企业级开发中的几种常见业务场景. 先来看一下我的控 ...
- PHP 笔记——文件引用
1. 文件路径 "文件路径"指的是被包含文件所在的绝对路径或相对路径. 在相对路径中,"./"表示当前目录,"../"表示当前目录的上级目录 ...
- BZOJ 4003: [JLOI2015]城池攻占 左偏树 可并堆
https://www.lydsy.com/JudgeOnline/problem.php?id=4003 感觉就是……普通的堆啊(暴论),因为这个堆是通过递归往右堆里加一个新堆或者新节点的,所以要始 ...
- zookeeper【3】服务发现
服务发现:指对集群中的服务上下线做统一管理,每个工作服务器都可以作为数据的发布方,向集群注册自己的基本信息,而让某些监控服务器作为订阅方,订阅工作服务器的基本信息.当工作服务器的基本信息改变时,如服务 ...
- codevs 1063 合并果子 STL 优先队列
1063 合并果子 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codevs.cn/problem/1063/ Description 在一 ...
- 使用Django来处理对于静态文件的请求
引言 本方法适用于linux+python2.7+django1.2,使用django自带的web服务. 同样也适用于sina app engine. 1.准备工作 准备css文件,准备js文件,准备 ...
- Android native层动态库注射
1.简单介绍 本文解说在Android native层.root权限下.注射动态库到目标进程,从而hook目标进程中动态库的函数的实现方式. 文中的源代码所有来源于网络.我仅仅是略微加以整理. 环境: ...
- Android学习网站(1)
收集了一些比较好的Android学习网站,希望对大家有所帮助: 1.http://developer.android.com/ Android官方网站,可惜被屏蔽了,需要使用FQ软件 2.http:/ ...
- 光速 React
光速 React Vixlet 团队优化性能的经验教训 在过去一年多,我们 Vixlet 的 web 团队已经着手于一个激动人心的项目:将我们的整个 web 应用迁移到 React + Redux 架 ...
- 使用Bootstrap 3开发响应式网站实践01,前期准备、导航区域等
"使用Bootstrap 3开发响应式网站实践"系列,将使用Bootstrap 3.2制作一个自适应网站,无论是在电脑.平板,还是手机上,都呈现比较好的效果.在电脑浏览器上的最终效 ...