【问题标题】:Pass result of functional chain to function将函数链的结果传递给函数
【发布时间】:2017-05-23 08:19:51
【问题描述】:

如果我有一个数组someArray,我首先要对其进行一些操作,然后将该结果传递给一个函数arrfun,该函数将数组作为参数。像下面这样

let arr = someArray.filter(foo).map(bar)
let result = arrfun(arr)

在上面的场景中,我想避免必须分配一个中间变量来传递给arrfun。我想要这样的东西。

Object.prototype.pipe = function(f) {return f(this)}

let result = someArray.filter(foo).map(bar).pipe(arrfun)
  • 代替.pipe(),您将如何解决这个问题?
  • 将该功能引入Object 是否明智?
  • pipe 是此类函数的最佳名称吗? chain? pass?

新示例

const pc = options => options
  .join(' ')
  .match(/--[\w.]* [\w.]*/g)
  .map(s => s.slice(2).split(' '))
  .map(([key, value]) => ({key, value}))
  .map(nestObject)
  .reduce((acc, val) => Object.assign(acc, val), {})

const nestObject = ({key, value}) => key
  .split('.')
  .reverse()
  .reduce((inner, key) => ({[key]: inner}), value)

在上面的示例中,如果没有找到匹配项,.match 会返回 null。使用 .pipe 你可以解决它 ny 将该行更改为

.pipe(s => s.match(/--[\w.]* [\w.]*/g) || [])

如果没有pipe,你会如何解决这个问题?

【问题讨论】:

  • arrfun(someArray.filter(foo).map(bar)) 有什么问题?
  • 如果你真的想在Object.prototype上引入新方法,至少do it properly(但不是,it's not sensible)。
  • chain 有不同的含义
  • (options.join(…).match(…) || []).map(…).… 有什么问题?
  • 因为,在我看来,包装这样的东西并不能提高可读性。我认为在这个例子中,被包装的东西已经很大了,想象有更多的包装器。只是链接东西要简单得多。

标签: javascript functional-programming


【解决方案1】:

在上述情况下,我希望避免分配一个中间变量以传递给arrfun

你是否忽略了这个简单直接的表达方式?

let result = arrfun(someArray.filter(foo).map(bar))

从右到左的函数组合

或者您可能希望经典(从右到左)函数组合?

const compose = (f,...fs) => x =>
  f === undefined ? x : f(compose(...fs)(x))

const filter = f => xs =>
  xs.filter(x => f(x))

const map = f => xs =>
  xs.map(x => f(x))

const foo = x =>
  x > 3
  
const bar = x =>
  x * x
  
const arrfun = xs =>
  xs.reverse()

const myfunc =
  compose(arrfun, map(bar), filter(foo))

let someArray = [1,2,3,4,5,6]

let result = myfunc(someArray)

console.log(result)
// [ 36, 25, 16 ]

从左到右的函数组合

使用从左到右的函数组合与上述相同的答案

const compose = (f,...fs) => x =>
  f === undefined ? x : compose(...fs)(f(x))

const filter = f => xs =>
  xs.filter(x => f(x))

const map = f => xs =>
  xs.map(x => f(x))

const foo = x =>
  x > 3
  
const bar = x =>
  x * x
  
const arrfun = xs =>
  xs.reverse()

// notice order of functions
const myfunc =
  compose(filter(foo), map(bar), arrfun)
  
let someArray = [1,2,3,4,5,6]

let result = myfunc(someArray)

console.log(result)
// [ 36, 25, 16 ]

恒等函子

我不认为将整个内容包装在可读性方面。想象一下,您必须将更多内容链接到 arrfun,然后将其包装在另一个函数中。

你应该看到 this answer 我写的关于 Identity 函子 - 这给你一个可链接的接口,但不涉及原生原型

const Identity = x => ({
  runIdentity: x,
  map: f => Identity(f(x))
})

const foo = x =>
  x > 3
  
const bar = x =>
  x * x
  
const arrfun = xs =>
  xs.reverse()

const myfunc = xs =>
  Identity(xs)
    .map(xs => xs.filter(foo))
    .map(xs => xs.map(bar))
    .map(xs => arrfun(xs))
    .runIdentity

let someArray = [1,2,3,4,5,6]

let result = myfunc(someArray)

console.log(result)
// [ 35, 25, 16 ]

当然,如果你保留filtermap 就像我们之前定义的那样,它会清理myfunc 的定义

const Identity = x => ({
  runIdentity: x,
  map: f => Identity(f(x))
})

const filter = f => xs =>
  xs.filter(x => f(x))

const map = f => xs =>
  xs.map(x => f(x))

const foo = x =>
  x > 3
  
const bar = x =>
  x * x
  
const arrfun = xs =>
  xs.reverse()

const myfunc = x =>
  Identity(x)
    .map(filter(foo))
    .map(map(bar))
    .map(arrfun)
    .runIdentity

let someArray = [1,2,3,4,5,6]

let result = myfunc(someArray)

console.log(result)
// [ 35, 25, 16 ]

并且不要挂断foobar 是预先定义的。如果您愿意,我们可以直接在 myfunc 中使用 lambda 表达式

const myfunc = xs =>
  Identity(xs)
    .map(xs => xs.filter(x => x > 3))
    .map(xs => xs.map(x => x * x))
    .map(arrfun)
    // or skip defining arrfun somewhere else and just ...
    // .map(xs => xs.reverse())
    .runIdentity

【讨论】:

  • 我不认为包装整个事情会在可读性方面进行扩展。想象一下,您必须将更多的东西链接到 arrfun,然后将这些东西包装在另一个函数中。不过,我可能忽略了构图。唯一可能是一个缺点可能是我必须先定义函数然后编写(可能也是一件好事)。
  • 我更新了我的答案以解决您的评论。 Identity 仿函数 非常适合在不触及原生原型的情况下制作可链接的界面。让我知道是否可以进一步帮助您^_^
  • 关于您的评论编辑,foobar 不需要预定义 - 它们可以是直接用 myfunc 编写的 lambda 表达式
  • 很好的例子,在那里学到了一些好东西,谢谢。我在帖子中添加了一个有点不同的额外示例。
【解决方案2】:

您可以首先将您的操纵器函数和结果函数组合为可重用函数。喜欢:

let arr = [1,2,3,4,5];
const manipulatorFn = arr => arr.map(item => item +1);
const arrFunc = (arr, fn) => fn(arr);

或者如果你想在 arrFunc 中做更多的事情

const arrFunc = (arr, fn) => {
  let a = fn(arr);

  // do some more stuff with a
  return a;
};

现在您可以获取结果

let result = arrFunc(arr, manipulatorFn);

【讨论】:

    猜你喜欢
    • 2021-12-27
    • 1970-01-01
    • 2013-05-21
    • 1970-01-01
    • 2021-03-17
    • 2019-05-12
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    相关资源
    最近更新 更多