为什么 R.ifElse 没有返回 Promise?
Why is R.ifElse not returning a Promise?
任务
我需要制作一个应用程序来读取 CSV 文件,转换其数据,然后将其输出为另一个 CSV 文件。
输入格式如下:
13:25:37 up 19 days, 21:35, 4 users, load average: 0.02, 0.02, 0.00
13:25:38 up 19 days, 21:35, 4 users, load average: 0.02, 0.02, 0.00
... so on
对于那些 UNIX 爱好者,您会认出这是控制台命令的输出 uptime
。
我想要的输出格式如下:
RowNum, Avg Load
1,0.02
2,0.02
其中第一列是CSV中的行号,第二列是load average的数字部分:0.02。
将忽略所有其他列。
问题
为了尽我所能做到这一点,我决定使用 ramda。
至少可以说,这是……一个挑战。现在,我的代码有几个结构问题,但我想关注 main
函数,它不起作用。每次执行我的代码时,我都会收到错误消息:
index.js:54
.then( () => console.log("Done!") )
^
TypeError: main(...).then is not a function
这令人困惑,因为在两个函数中,我传递给 R.ifElse
我 return 一个 Promise。
代码
const fs = require("fs");
const csvReader = require("csvreader");
const R = require("ramda");
const isString = require("lodash.isstring");
const { promisify } = require("util");
const argv = require("minimist")(process.argv.slice(2));
const appedFileAsync = promisify( fs.appendFile );
const createProcessData = () => {
const stringifyArray = array => `${array.toString()}\n`;
const write = str => fs.appendFileSync( argv.outputFile, str );
const getAvg = R.pipe(
R.replace("load average:", ""),
R.trim
);
let elapsedTime = 1;
const transform = list => [ elapsedTime++, getAvg ( R.nth( 3, list ) ) ];
return R.pipe(
transform,
stringifyArray,
write
);
};
const printHelp = () => {
console.log(`
=== MAN HELP ===
Usage: npm start -- --inputFile input.csv --outputFile output.csv
--inputFile: location of an input file in CSV format
--outputFile: location of an output file to append the new information to.
If this file does not exist, it will be created.
`);
return Promise.resolve();
};
const execute = () => appedFileAsync( argv.outputFile, "Time, Avg Load\n" )
.then( ( ) => csvReader.read( argv.inputFile, createProcessData() ) );
const main = () => {
const isInvalidFileName = R.anyPass( [ R.isNil, R.isEmpty, R.pipe ( isString, R.not ) ] );
const hasInvalidArgs = R.either( isInvalidFileName( argv.inputFile ), isInvalidFileName( argv.outputFile ) );
return R.ifElse(
hasInvalidArgs,
printHelp,
execute
);
};
main()
.then( () => console.log("Done!") )
.catch( console.error );
问题
- 我的代码有什么问题?
这是ifElse
的想法:
const ifElse = (predicate, consequent, alternative) =>
(...val) => predicate(...val) ? consequent(...val) : alternative(...val);
所以
const comp = ifElse(
(a, b) => a < b,
(a, b) => `${a} is smaller than ${b}`,
(a, b) => `${a} is at least as large as ${b}`
)
comp(12, 7) //=> "12 is at least as large as 7"
要点是 ifElse
的第一个参数是 函数 。但是你传递给它的结果是:
R.either( isInvalidFileName( argv.inputFile ), isInvalidFileName( argv.outputFile ) )
现在正常,either
returns一个函数。但这取决于您为其提供功能。假设是,如果您不提供函数,您知道自己在做什么,并且正在使用 ap
和 map
方法提供容器类型,因此 either
稍微更通用。但是您提供的是布尔值,例如 isInvalidFileName( argv.inputFile )
的结果。在这一点上,行为没有明确定义。也许这应该改变,但 Ramda 的理念通常是垃圾进垃圾出。因此,无论出于何种原因,either
调用都会返回 [undefined]
.
这意味着您提供 [undefined]
作为 ifElse
的谓词函数。当您尝试调用它时,您应该会收到错误消息。我没有试图追查为什么您看到的那个错误被掩盖了。
至于如何使用 Ramda 解决这个问题,我不太确定从哪里开始。这与 Ramda 一贯的风格相去甚远。如果不出意外,不接受任何参数的函数在 Ramda 中是极其罕见的。我想我会用一个接受 argv.inputFile
和 argv.outputFile
的函数来启动 Ramda 部分,无论是作为单个对象还是作为单个对象 argv
.
任务
我需要制作一个应用程序来读取 CSV 文件,转换其数据,然后将其输出为另一个 CSV 文件。
输入格式如下:
13:25:37 up 19 days, 21:35, 4 users, load average: 0.02, 0.02, 0.00
13:25:38 up 19 days, 21:35, 4 users, load average: 0.02, 0.02, 0.00
... so on
对于那些 UNIX 爱好者,您会认出这是控制台命令的输出 uptime
。
我想要的输出格式如下:
RowNum, Avg Load
1,0.02
2,0.02
其中第一列是CSV中的行号,第二列是load average的数字部分:0.02。
将忽略所有其他列。
问题
为了尽我所能做到这一点,我决定使用 ramda。
至少可以说,这是……一个挑战。现在,我的代码有几个结构问题,但我想关注 main
函数,它不起作用。每次执行我的代码时,我都会收到错误消息:
index.js:54
.then( () => console.log("Done!") )
^
TypeError: main(...).then is not a function
这令人困惑,因为在两个函数中,我传递给 R.ifElse
我 return 一个 Promise。
代码
const fs = require("fs");
const csvReader = require("csvreader");
const R = require("ramda");
const isString = require("lodash.isstring");
const { promisify } = require("util");
const argv = require("minimist")(process.argv.slice(2));
const appedFileAsync = promisify( fs.appendFile );
const createProcessData = () => {
const stringifyArray = array => `${array.toString()}\n`;
const write = str => fs.appendFileSync( argv.outputFile, str );
const getAvg = R.pipe(
R.replace("load average:", ""),
R.trim
);
let elapsedTime = 1;
const transform = list => [ elapsedTime++, getAvg ( R.nth( 3, list ) ) ];
return R.pipe(
transform,
stringifyArray,
write
);
};
const printHelp = () => {
console.log(`
=== MAN HELP ===
Usage: npm start -- --inputFile input.csv --outputFile output.csv
--inputFile: location of an input file in CSV format
--outputFile: location of an output file to append the new information to.
If this file does not exist, it will be created.
`);
return Promise.resolve();
};
const execute = () => appedFileAsync( argv.outputFile, "Time, Avg Load\n" )
.then( ( ) => csvReader.read( argv.inputFile, createProcessData() ) );
const main = () => {
const isInvalidFileName = R.anyPass( [ R.isNil, R.isEmpty, R.pipe ( isString, R.not ) ] );
const hasInvalidArgs = R.either( isInvalidFileName( argv.inputFile ), isInvalidFileName( argv.outputFile ) );
return R.ifElse(
hasInvalidArgs,
printHelp,
execute
);
};
main()
.then( () => console.log("Done!") )
.catch( console.error );
问题
- 我的代码有什么问题?
这是ifElse
的想法:
const ifElse = (predicate, consequent, alternative) =>
(...val) => predicate(...val) ? consequent(...val) : alternative(...val);
所以
const comp = ifElse(
(a, b) => a < b,
(a, b) => `${a} is smaller than ${b}`,
(a, b) => `${a} is at least as large as ${b}`
)
comp(12, 7) //=> "12 is at least as large as 7"
要点是 ifElse
的第一个参数是 函数 。但是你传递给它的结果是:
R.either( isInvalidFileName( argv.inputFile ), isInvalidFileName( argv.outputFile ) )
现在正常,either
returns一个函数。但这取决于您为其提供功能。假设是,如果您不提供函数,您知道自己在做什么,并且正在使用 ap
和 map
方法提供容器类型,因此 either
稍微更通用。但是您提供的是布尔值,例如 isInvalidFileName( argv.inputFile )
的结果。在这一点上,行为没有明确定义。也许这应该改变,但 Ramda 的理念通常是垃圾进垃圾出。因此,无论出于何种原因,either
调用都会返回 [undefined]
.
这意味着您提供 [undefined]
作为 ifElse
的谓词函数。当您尝试调用它时,您应该会收到错误消息。我没有试图追查为什么您看到的那个错误被掩盖了。
至于如何使用 Ramda 解决这个问题,我不太确定从哪里开始。这与 Ramda 一贯的风格相去甚远。如果不出意外,不接受任何参数的函数在 Ramda 中是极其罕见的。我想我会用一个接受 argv.inputFile
和 argv.outputFile
的函数来启动 Ramda 部分,无论是作为单个对象还是作为单个对象 argv
.