javascript - Ramda/函数式编程的基础知识
问题描述
有效的部分
我已经阅读了很多文章并观看了一些关于 JavaScript 中 FP 的讨论,并决定试一试。
我知道这是基本的东西,但再来一次?开始:
const easy = [
0,0,4,6,7,2,0,0,0,
5,0,0,8,0,0,0,9,6,
0,6,3,0,4,0,0,0,8,
3,8,2,1,0,0,9,6,0,
4,7,5,0,0,0,1,0,0,
9,1,0,2,0,4,5,0,0,
0,0,0,0,0,0,0,2,9,
0,0,1,0,0,0,7,4,3,
2,0,0,0,6,3,8,0,1
];
const expandSudoku = R.map(
R.ifElse(
R.equals(0),
R.always(R.range(1,10));
R.of
)
);
console.log(expandSudoku(easy));
这需要一个数字数组并将其映射到一个数组数组中。
- 0 -> [1,2,3,4,5,6,7,8,9]
- n -> [n]
R.equals 让我很困惑
如果我错了,请纠正我,但这实际上是同一件事(使用一些匿名包装函数):
const easy = [
0,0,4,6,7,2,0,0,0,
5,0,0,8,0,0,0,9,6,
0,6,3,0,4,0,0,0,8,
3,8,2,1,0,0,9,6,0,
4,7,5,0,0,0,1,0,0,
9,1,0,2,0,4,5,0,0,
0,0,0,0,0,0,0,2,9,
0,0,1,0,0,0,7,4,3,
2,0,0,0,6,3,8,0,1
];
const expandSudoku = R.map(v =>
R.ifElse(
x => R.equals(0)(x),
x => R.range(1,10),
x => R.of(x)
)(v)
);
console.log(expandSudoku(easy));
R.equals(0)(x)
第一个问题:如果我更改为 ,为什么会出现错误R.equals(0, x)
?我想以 Ramda 的咖喱风格,那些应该是一样的。这只是打字稿吗?编译后的 JavaScript 运行良好。
错误: '(x: any) => (a: any) => boolean' 类型的参数不可分配给'Pred' 类型的参数。
通过第二个参数?
我有这个辅助功能:
const pass2nd = R.curry((fn, arg1, arg2) => fn(arg2));
我这样使用过:
const indexToCoord = R.applySpec({
x: R.modulo(R.__,9),
y: R.compose(Math.floor, R.divide(R.__,9))
});
const makeCell = R.applySpec({
coord: pass2nd(indexToCoord), // pass2nd to only get the second argument
options: R.unary(R.ifElse( // Unary to only get the first argument
R.equals(0),
R.always(R.range(1,10)),
R.of
))
});
const mapIndexed = R.addIndex(R.map);
const expandSudoku = mapIndexed(makeCell);
console.log(expandSudoku(easy));
Ramda 有类似的东西吗?那是代码气味吗?这是怎么回事?
最后:
什么时候成分太多了?是
const indexToCoord = R.applySpec({
x: R.modulo(R.__,9),
y: R.compose(Math.floor, R.divide(R.__,9))
});
一般优于
const indexToCoord = v => ({
x: v % 9,
y: Math.floor(v/9)
});
?
解决方案
R.equals(0)(x)
第一个问题:如果我更改为 ,为什么会出现错误R.equals(0, x)
?我想以 Ramda 的咖喱风格,那些应该是一样的。这只是打字稿吗?编译后的 JavaScript 运行良好。
它们应该是相同的,如果 JS 运行良好,那么这绝对是一个 TS 问题。恐怕我对 TS 的了解还不够,无法告诉您如何解决它。
我有这个辅助功能:
const pass2nd = R.curry((fn, arg1, arg2) => fn(arg2));
[ ... ] Ramda 有类似的东西吗?那是代码气味吗?这是怎么回事?
您可以nthArg
以类似的方式使用。但我倾向于觉得,如果我必须达到这一点,那么我就会努力让一些不需要的东西免积分。(与useWith
其他一些 Ramda 函数类似。)
什么时候成分太多了?是
const indexToCoord = R.applySpec({ x: R.modulo(R.__,9), y: R.compose(Math.floor, R.divide(R.__,9)) });
一般优于
const indexToCoord = v => ({ x: v % 9, y: Math.floor(v/9) });
?
我会说很多相反的。您的第二个功能非常易读。在我看来,采用免点样式的唯一重要原因是使代码更具可读性。这不这样做,我不会打扰。
另一个警告。在这:
const expandSudoku = R.map(
R.ifElse(
R.equals(0),
R.always(R.range(1,10)),
R.of
)
)
的使用always
可能有问题。这取决于您如何使用结果。但是许多数独系统使用了相当多的变异来简化性能所需的内容。如果您这样做,您应该知道它always
只是返回提供的缓存值。它不是克隆。如果您以这种方式使用它并选择对结果数组进行变异,则每次0
替换都会对其进行变异。
如果这是一个问题,thunkify
可能会做出更好的选择:
const expandSudoku = R.map(
R.ifElse(
R.equals(0),
R.thunkify (R.range) (1, 10),
R.of
)
)
基本上thunkify (fn) (...args)
产生相当于() => fn (...args)
. 这比always
存在突变时要安全得多。
当然,如果您所做的一切都是不变的,那么恭喜!我很想看看结果。
推荐阅读
- apache-spark - 如何强制 Spark Dataframe 在所有工作节点之间拆分?
- maven - 设置 project.build.sourceDirectory 是否适用于 Maven 属性?
- javascript - 光标位置在 Firefox 中使用 div contenteditable 结束
- c# - 有没有一种干净的方法可以从 appsettings.json 获取属性,并在类属性中使用它们?
- ssl - 使用 Pyspark 通过 SSL 连接到 DB2
- javascript - 如何使用捕获错误处理角度错误
- html - 三列CSS滚动表布局错误
- reactjs - 我应该使用 TypeScript 输入什么类型的 react-bootstrap 事件?
- commercetools - 如何在商务工具中使用“Like”谓词
- android - 运行 Android 应用 (APK) 时,如何从内存中获取基地址?