【问题标题】:Converting multi-parameter function to point-free style using Ramda使用 Ramda 将多参数函数转换为无点样式
【发布时间】:2017-03-29 06:10:09
【问题描述】:

使用Ramda,出于教育和文体原因,我正在尝试将一个相当大的函数转换为无点函数。

该函数有 4 个参数,一个 ES6 ma​​p,一个接受一个对象并返回一个对象的 domainModel 函数,一个 key 属性识别地图上设置的内容,以及由 domainModel 调用后在地图上设置的 json 属性。

const setNewDomainModelOnMap = curry((map, domainModel, key, json) => map.set(key, domainModel(json)));

现在,我已经对函数进行了 curried,以获得一些功能上的好处,但如果可能的话,我想使用无参数版本。我已经成功地在具有较少参数的函数上采用了无点风格,无法完全找出接近这个的正确角度。

【问题讨论】:

  • 我没有看到任何好的方法来做到这一点。无论我们创建什么无点解决方案,都可能比您那里的解决方案清晰得多。是否有任何令人信服的理由让它免积分?
  • 在担心默认定义之前,您可能会认为您的函数是不纯的——如果您使用 ES6 Map 而不是(例如)Immutable.Map,map 会发生变异
  • @ScottSauyet - 可能,但我一直在学习 Ramda 尝试将我的应用程序转换为无点样式......迫使我尝试使用尽可能多的 API!
  • @naomik - 这里的背景故事是 MobX 采用可变映射来处理状态。一点点可变性对我来说还是可以的
  • @user1787531 您以非常定性的方式谈论函数式编程:“风格”“为函数式优点而柯里化”“很少有点可变性是可以的” - 我担心你缺少一个坚实的基础,可以让你以更具体的方式理解这些概念。关于可变性的具体讨论超出了本评论部分的范围,但我建议您在担心问题中提出的一些主题之前花更多时间了解基础知识。

标签: javascript functional-programming ramda.js


【解决方案1】:

专业化功能

currying 的全部意义在于它允许您使用绑定的每个参数来专门化函数。这使我们可以编写通用函数,这些函数可以以多种方式进行专门化

const mult = x => y => x * y
const double = mult (2)
const triple = mult (3)
const negate = mult (-1)

console.log(double(5)) // 10
console.log(triple(5)) // 15
console.log(negate(5)) // -5

您有一个名为setNewDomainModelOnMap 的函数,它有一个非常专业的名称,但该函数本身非常具体——它没有任何通用性。

如果您编写了一个 generic 函数,该函数可以根据您提供的参数进行专门化怎么办?

// maybe something liek this would be better
const myfunc = set (someKey, someValue)
const updatedMap = myFunc (oldMap)

横向思考

set 怎么样?

你的函数的性质是在地图上设置一个值——这个值被某个函数domainModel增加的事实并不意味着它必须是你的集合的一个参数功能

const set = curry((key, value, map) =>
  map.set(key, value)
)

set(someKey, domainModel(json), someMap)
// => Map { ... }

不,如果你的函数不会变成嵌套 compose 调用的灾难,你就不能再删除任何点了——尤其是因为你正在包装一个方法 (map.set),这会使保存上下文变得更加复杂。


Ramda 同意这很有用

Ramda 实际上有它自己的set 函数,该函数对镜头、一些值和一些对象进行操作。

var xLens = R.lensProp('x');

R.set(xLens, 4, {x: 1, y: 2});  //=> {x: 4, y: 2}
R.set(xLens, 8, {x: 1, y: 2});  //=> {x: 8, y: 2}

鉴于此,如果您担心命名冲突,您可能希望将您的函数命名为 mapSet

【讨论】:

  • 不错的解构naomik!如果问题出在包装的方法调用上,你能做这样的事情来使它更可组合吗? const mapSet = invoke(2, "set")...
  • 它的定义方式同样可组合,但当然,您可以使用R.invoker 进行相同的定义。我认为这会损害可读性并掩盖某些意图,但这是个人意见。
  • @user1787531 我对帖子的开头进行了编辑,这可能有助于您理解柯里化
  • @user1787531 这与未绑定参数的数量无关。组合最适合一元函数,并且所有柯里化函数都是一元函数(或一元函数序列)。考虑repl: GjS9——柯里化是关于抽象而不是arity;我们不知道一个函数何时“完成”,因为另一个函数可能是另一个函数计算的有效结果。如果是这样,该函数可以有效地计算另一个函数,依此类推。
  • (cont'd) 另一方面,组合是关于对一元函数进行排序,而不考虑任何未绑定的参数。当你处理一个咖喱函数时,你根本不应该考虑 args 的数量。只知道它现在需要一个参数,并且有一些返回值。该返回值可以是任何东西,包括另一个函数——所以是的,这些概念相互协调,但不是以任何僵化的方式。
猜你喜欢
  • 1970-01-01
  • 2017-01-24
  • 2017-10-07
  • 1970-01-01
  • 2018-06-23
  • 2018-08-11
  • 2018-11-12
  • 1970-01-01
  • 2021-11-08
相关资源
最近更新 更多