javascript - 在 JavaScript 中将函数映射到生成器

标签 javascript functional-programming generator

我在 JavaScript 中有一个名为 generateNumbers 的生成器和另一个生成器 generateLargerNumbers,它获取由 generateNumbers 生成的每个值并应用一个函数 addOne 给它,这样:

function addOne(value) {
  return value + 1
}

function* generateNumbers() {
  yield 1
  yield 2
  yield 3
}

function* generateLargerNumbers() {
  for (const number of generateNumbers()) {
    yield addOne(number)
  }
}

有没有什么简洁的方法可以在不从生成的值构建数组的情况下做到这一点?我在想类似的东西:

function* generateLargerNumbers() {
  yield* generateNumbers().map(addOne) // obviously doesn't work
}

最佳答案

高阶生成器

您可以选择自己操作生成器函数

const Generator =
  {
    map: (f,g) => function* (...args)
      {
        for (const x of g (...args))
          yield f (x)
      },
    filter: (f,g) => function* (...args)
      {
        for (const x of g (...args))
          if (f (x))
            yield x
      }
  }

// some functions !
const square = x =>
  x * x

const isEven = x =>
  (x & 1) === 0
  
// a generator !
const range = function* (x = 0, y = 1)
  {
    while (x < y)
      yield x++
  }

// higher order generator !
for (const x of Generator.map (square, Generator.filter (isEven, range)) (0,10))
  console.log('evens squared', x)

高阶迭代器

或者你可以选择操作迭代器

const Iterator =
  {
    map: (f, it) => function* ()
      {
        for (const x of it)
          yield f (x)
      } (),
    filter: (f, it) => function* ()
      {
        for (const x of it)
          if (f (x))
            yield x
      } ()
  }

// some functions !
const square = x =>
  x * x
  
const isEven = x =>
  (x & 1) === 0

// a generator !
const range = function* (x = 0, y = 1)
  {
    while (x < y)
      yield x++
  }
  
// higher-order iterators !
for (const x of Iterator.map (square, Iterator.filter (isEven, range (0, 10))))
  console.log('evens squared', x)

推荐

在大多数情况下,我认为操作迭代器更实用,因为它具有定义良好(尽管不完善)的接口(interface)。它允许你做类似的事情

Iterator.map (square, Iterator.filter (isEven, [10,11,12,13]))

而另一种方法是

Generator.map (square, Generator.filter (isEven, Array.from)) ([10,11,12,13])

两者都有用例,但我发现前者比后者好得多


持久迭代器

JavaScript 的有状态迭代器让我很烦——每次对 .next 的后续调用都会不可逆地改变内部状态。

但是!没有什么能阻止您创建自己的迭代器,然后创建适配器以插入 JavaScript 的堆栈安全生成器机制

如果您对此感兴趣,您可能会喜欢此处提供的其他一些示例:Loop to a filesystem structure in my object to get all the files

唯一的好处不是我们可以重用一个持久迭代器,而是通过这个实现,后续读取甚至比第一次读取更快,因为内存 - 得分: JavaScript 0,持久迭代器 2

// -------------------------------------------------------------------
const Memo = (f, memo) => () =>
  memo === undefined
    ? (memo = f (), memo)
    : memo

// -------------------------------------------------------------------
const Yield = (value, next = Return) =>
  ({ done: false, value, next: Memo (next) })
  
const Return = value =>
  ({ done: true, value })
  
// -------------------------------------------------------------------
const MappedIterator = (f, it = Return ()) =>
  it.done
    ? Return ()
    : Yield (f (it.value), () => MappedIterator (f, it.next ()))
    
const FilteredIterator = (f, it = Return ()) =>
  it.done
    ? Return ()
    : f (it.value)
      ? Yield (it.value, () => FilteredIterator (f, it.next ()))
      : FilteredIterator (f, it.next ())

// -------------------------------------------------------------------
const Generator = function* (it = Return ())
  {
    while (it.done === false)
      (yield it.value, it = it.next ())
    return it.value
  }

// -------------------------------------------------------------------  
const Range = (x = 0, y = 1) =>
  x < y
    ? Yield (x, () => Range (x + 1, y))
    : Return ()

const square = x =>
  x * x

const isEven = x =>
  (x & 1) === 0

// -------------------------------------------------------------------
for (const x of Generator (MappedIterator (square, FilteredIterator (isEven, Range (0,10)))))
  console.log ('evens squared', x)

关于javascript - 在 JavaScript 中将函数映射到生成器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45983883/

相关文章:

java - 从嵌套列表创建 map

python - 生成器、yield、发送 python

javascript - jQuery 获取无法作为对象访问的数据

jquery - jQuery 是一个 monad

javascript - Immutable.js 中的延迟连接?

php - PHP 中的产量是什么意思?

python - 如何使 itertools.tee() 生成迭代元素的副本?

javascript - 是否有仅用于页面转换的 jQuery Mobile 的轻型替代品?

javascript - 无法读取属性 'transition' null chartjs

javascript - Photoshop 选择脚本