映射 Javascript 中的一组任务
Mapping over an array of Tasks in Javascript
所以我开始研究 Ramda / Folktale。我在尝试映射来自目录的一系列任务时遇到问题。我正在尝试解析文件内容。
var fs = require('fs');
var util = require('util');
var R = require('ramda');
var Task = require('data.task');
var compose = R.compose;
var map = R.map;
var chain = R.chain;
function parseFile(data) {
console.log("Name: " + data.match(/$name:(.*)/)[1]);
console.log("Description: " + data.match(/$description:(.*)/)[1]);
console.log("Example path: " + data.match(/$example:(.*)/)[1]);
}
// String => Task [String]
function readDirectories(path) {
return new Task(function(reject, resolve) {
fs.readdir(path, function(err, files) {
err ? reject(err) : resolve(files);
})
})
}
// String => Task String
function readFile(file) {
return new Task(function(reject, resolve) {
fs.readFile('./src/less/' + file, 'utf8', function(err, data) {
err ? reject(err) : resolve(data);
})
})
}
var app = compose(chain(readFile), readDirectories);
app('./src/less').fork(
function(error) { throw error },
function(data) { util.log(data) }
);
我正在读取目录中的文件并返回任务。当这个问题解决时,它应该进入 readFile 函数(returns 一个新任务)。一旦它读取文件,我希望它只解析其中的一些位。
具有以下内容:
var app = compose(chain(readFile), readDirectories);
它进入了 readFile 函数,但是 'file' 是一个文件数组,所以它出错了。
有:
var app = compose(chain(map(readFile)), readDirectories);
我们永远不会进入 fs.readfile(),但 'file' 是实际的文件名。
我对此很困惑,文档也令人费解。欢迎任何建议。
谢谢
'use strict';
const fs = require('fs');
const Task = require('data.task');
const R = require('ramda');
// parseFile :: String -> { name :: String
// , description :: String
// , example :: String }
const parseFile = data => ({
name: R.nth(1, R.match(/[$]name:(.*)/, data)),
description: R.nth(1, R.match(/[$]description:(.*)/, data)),
example: R.nth(1, R.match(/[$]example:(.*)/, data)),
});
// readDirectories :: String -> Task (Array String)
const readDirectories = path =>
new Task((reject, resolve) => {
fs.readdir(path, (err, filenames) => {
err == null ? resolve(filenames) : reject(err);
})
});
// readFile :: String -> Task String
const readFile = filename =>
new Task(function(reject, resolve) {
fs.readFile('./src/less/' + filename, 'utf8', (err, data) => {
err == null ? resolve(data) : reject(err);
})
});
// dirs :: Task (Array String)
const dirs = readDirectories('./src/less');
// files :: Task (Array (Task String))
const files = R.map(R.map(readFile), dirs);
// sequenced :: Task (Task (Array String))
const sequenced = R.map(R.sequence(Task.of), files);
// unnested :: Task (Array String)
const unnested = R.unnest(sequenced);
// parsed :: Task (Array { name :: String
// , description :: String
// , example :: String })
const parsed = R.map(R.map(parseFile), unnested);
parsed.fork(err => {
process.stderr.write(err.message);
process.exit(1);
},
data => {
process.stdout.write(R.toString(data));
process.exit(0);
});
我将每个转换写在单独的行中,这样我就可以包含类型签名,使嵌套映射更容易理解。这些当然可以通过 R.pipe
.
组合成一个管道
最有趣的步骤是使用 R.sequence
to transform Array (Task String)
into Task (Array String)
, and using R.unnest
将 Task (Task (Array String))
转换为 Task (Array String)
。
如果您还没有看过 plaid/async-problem,我建议您看看。
正如 David 所建议的那样,commute
可用于将一些应用程序列表(例如 Task
)转换为包含值列表的单个应用程序。
var app = compose(chain(map(readFile)), readDirectories);
We never get into fs.readfile(), but 'file' is the actual file name.
密切相关的 commuteMap
也可以在这里提供帮助,因为它将处理单独的 map
步骤,这意味着上面的代码也应该能够表示为:
var app = compose(chain(commuteMap(readFile, Task.of)), readDirectories);
我遇到了读取目录中所有文件的类似问题,并从 ramda 的 pipeP 开始:
'use strict';
const fs = require('fs');
const promisify = require("es6-promisify");
const _ = require('ramda');
const path = './src/less/';
const log = function(x){ console.dir(x); return x };
const map = _.map;
const take = _.take;
const readdir = promisify(fs.readdir);
const readFile = _.curry(fs.readFile);
const readTextFile = readFile(_.__, 'utf8');
const readTextFileP = promisify(readTextFile);
var app = _.pipeP(
readdir,
take(2), // for debugging, so don’t waste time reading all the files
map(_.concat(path)),
map(readTextFileP),
promiseAll,
map(take(50)),
log
);
function promiseAll(arr) {
return Promise.all(arr)
}
app(path);
Promise.all 在读取文件时似乎是必需的,因为 pipeP 需要一个值或一个承诺,但正在接收一组读取文件的承诺。令我困惑的是为什么我必须将函数 return 设为 Promise.all
而不是内联它。
你对 task/fork 的用法很有趣,因为内置了错误处理功能。希望 pipeP 有一个 catch 块,因为没有它就需要注入 maybe,这对像我这样的初学者来说很难做到对了。
所以我开始研究 Ramda / Folktale。我在尝试映射来自目录的一系列任务时遇到问题。我正在尝试解析文件内容。
var fs = require('fs');
var util = require('util');
var R = require('ramda');
var Task = require('data.task');
var compose = R.compose;
var map = R.map;
var chain = R.chain;
function parseFile(data) {
console.log("Name: " + data.match(/$name:(.*)/)[1]);
console.log("Description: " + data.match(/$description:(.*)/)[1]);
console.log("Example path: " + data.match(/$example:(.*)/)[1]);
}
// String => Task [String]
function readDirectories(path) {
return new Task(function(reject, resolve) {
fs.readdir(path, function(err, files) {
err ? reject(err) : resolve(files);
})
})
}
// String => Task String
function readFile(file) {
return new Task(function(reject, resolve) {
fs.readFile('./src/less/' + file, 'utf8', function(err, data) {
err ? reject(err) : resolve(data);
})
})
}
var app = compose(chain(readFile), readDirectories);
app('./src/less').fork(
function(error) { throw error },
function(data) { util.log(data) }
);
我正在读取目录中的文件并返回任务。当这个问题解决时,它应该进入 readFile 函数(returns 一个新任务)。一旦它读取文件,我希望它只解析其中的一些位。
具有以下内容:
var app = compose(chain(readFile), readDirectories);
它进入了 readFile 函数,但是 'file' 是一个文件数组,所以它出错了。
有:
var app = compose(chain(map(readFile)), readDirectories);
我们永远不会进入 fs.readfile(),但 'file' 是实际的文件名。
我对此很困惑,文档也令人费解。欢迎任何建议。
谢谢
'use strict';
const fs = require('fs');
const Task = require('data.task');
const R = require('ramda');
// parseFile :: String -> { name :: String
// , description :: String
// , example :: String }
const parseFile = data => ({
name: R.nth(1, R.match(/[$]name:(.*)/, data)),
description: R.nth(1, R.match(/[$]description:(.*)/, data)),
example: R.nth(1, R.match(/[$]example:(.*)/, data)),
});
// readDirectories :: String -> Task (Array String)
const readDirectories = path =>
new Task((reject, resolve) => {
fs.readdir(path, (err, filenames) => {
err == null ? resolve(filenames) : reject(err);
})
});
// readFile :: String -> Task String
const readFile = filename =>
new Task(function(reject, resolve) {
fs.readFile('./src/less/' + filename, 'utf8', (err, data) => {
err == null ? resolve(data) : reject(err);
})
});
// dirs :: Task (Array String)
const dirs = readDirectories('./src/less');
// files :: Task (Array (Task String))
const files = R.map(R.map(readFile), dirs);
// sequenced :: Task (Task (Array String))
const sequenced = R.map(R.sequence(Task.of), files);
// unnested :: Task (Array String)
const unnested = R.unnest(sequenced);
// parsed :: Task (Array { name :: String
// , description :: String
// , example :: String })
const parsed = R.map(R.map(parseFile), unnested);
parsed.fork(err => {
process.stderr.write(err.message);
process.exit(1);
},
data => {
process.stdout.write(R.toString(data));
process.exit(0);
});
我将每个转换写在单独的行中,这样我就可以包含类型签名,使嵌套映射更容易理解。这些当然可以通过 R.pipe
.
最有趣的步骤是使用 R.sequence
to transform Array (Task String)
into Task (Array String)
, and using R.unnest
将 Task (Task (Array String))
转换为 Task (Array String)
。
如果您还没有看过 plaid/async-problem,我建议您看看。
正如 David 所建议的那样,commute
可用于将一些应用程序列表(例如 Task
)转换为包含值列表的单个应用程序。
var app = compose(chain(map(readFile)), readDirectories);
We never get into fs.readfile(), but 'file' is the actual file name.
密切相关的 commuteMap
也可以在这里提供帮助,因为它将处理单独的 map
步骤,这意味着上面的代码也应该能够表示为:
var app = compose(chain(commuteMap(readFile, Task.of)), readDirectories);
我遇到了读取目录中所有文件的类似问题,并从 ramda 的 pipeP 开始:
'use strict';
const fs = require('fs');
const promisify = require("es6-promisify");
const _ = require('ramda');
const path = './src/less/';
const log = function(x){ console.dir(x); return x };
const map = _.map;
const take = _.take;
const readdir = promisify(fs.readdir);
const readFile = _.curry(fs.readFile);
const readTextFile = readFile(_.__, 'utf8');
const readTextFileP = promisify(readTextFile);
var app = _.pipeP(
readdir,
take(2), // for debugging, so don’t waste time reading all the files
map(_.concat(path)),
map(readTextFileP),
promiseAll,
map(take(50)),
log
);
function promiseAll(arr) {
return Promise.all(arr)
}
app(path);
Promise.all 在读取文件时似乎是必需的,因为 pipeP 需要一个值或一个承诺,但正在接收一组读取文件的承诺。令我困惑的是为什么我必须将函数 return 设为 Promise.all
而不是内联它。
你对 task/fork 的用法很有趣,因为内置了错误处理功能。希望 pipeP 有一个 catch 块,因为没有它就需要注入 maybe,这对像我这样的初学者来说很难做到对了。