首页 > 解决方案 > 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));

这需要一个数字数组并将其映射到一个数组数组中。

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)
});

?

标签: javascripttypescriptramda.js

解决方案


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存在突变时要安全得多。

当然,如果您所做的一切都是不变的,那么恭喜!我很想看看结果。


推荐阅读