javascript - 如何映射任意 Iterables?

标签 javascript functional-programming ecmascript-6 iteration iterable

我为 Iterable 编写了一个 reduce 函数,现在我想派生一个可以映射到任意 Iterable 的通用 map 但是,我遇到了一个问题:由于 Iterable 抽象了数据源,map 无法确定它的类型(例如 ArrayStringMap 等)。我需要这种类型来调用相应的标识元素/concat 函数。我想到了三种解决方案:

  1. 显式传递标识元素/concat 函数const map = f => id => concat => xs(这很冗长并且会泄漏内部 API)
  2. 只映射实现了 monoid 接口(interface)的 Iterable(这很酷,但引入了新类型?)
  3. 依赖ArrayIteratorStringIterator等的原型(prototype)或构造函数标识

我尝试了后者,但无论做什么,isPrototypeOf/instanceof 总是产生 false,例如:

Array.prototype.values.prototype.isPrototypeOf([].values()); // false
Array.prototype.isPrototypeOf([].values()); // false

我的问题:

  • ArrayIterator/StringIterator/...的原型(prototype)在哪里?
  • 是否有更好的方法来解决给定问题?

编辑: [][Symbol.iterator]()("")[Symbol.iterator]() 似乎共享相同的原型(prototype):

Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())) ====
Object.getPrototypeOf(Object.getPrototypeOf(("")[Symbol.iterator]()))

通过原型(prototype)来区分似乎是不可能的。

编辑:这是我的代码:

const values = o => keys(o).values();
const next = iter => iter.next();

const foldl = f => acc => iter => {
  let loop = (acc, {value, done}) => done
   ? acc
   : loop(f(acc) (value), next(iter));

  return loop(acc, next(iter));
}


// static `map` version only for `Array`s - not what I desire

const map = f => foldl(acc => x => [...acc, f(x)]) ([]);


console.log( map(x => x + x) ([1,2,3].values()) ); // A

console.log( map(x => x + x) (("abc")[Symbol.iterator]()) ); // B

A 行中的代码产生了所需的结果。然而 B 产生一个 Array 而不是 String 并且连接只起作用,因为 StringNumber 在这方面恰好是等价的。

编辑: 我这样做的原因似乎很困惑:我想使用可迭代/迭代器协议(protocol)来抽象迭代细节,以便我的折叠/展开和派生映射/过滤器等功能是通用的。问题是,如果没有身份/连接协议(protocol),您将无法执行此操作。我依靠原型(prototype)身份的小“技巧”​​没有奏效。

@redneb 在他的回应中提出了一个很好的观点,我同意他的观点,即并非每个可迭代对象也是“可映射的”。但是,牢记这一点,我仍然认为以这种方式使用该协议(protocol)是有意义的 - 至少在 Javascript 中是这样,直到可能在未来的版本中有用于此类用法的可映射或收集协议(protocol)。

最佳答案

我没有用过iterable protocol以前,但在我看来,它本质上是一个接口(interface),旨在让您使用 for 循环迭代容器对象。问题是您正试图将该界面用于其设计目的以外的用途。为此,您需要一个单独的界面。可以想象,一个对象可能是“可迭代的”但不是“可映射的”。例如,假设在一个应用程序中我们正在使用二叉树,并且我们通过以 BFS 顺序遍历它们来为它们实现可迭代接口(interface),只是因为该顺序对这个特定应用程序有意义。通用 map 如何适用于这个特定的可迭代对象?它需要返回一个“相同形状”的树,但这个特定的可迭代实现没有提供足够的信息来重建树。

因此解决方案是定义一个新接口(interface)(将其命名为 MappableFunctor 或任何您喜欢的名称),但它必须是一个独特的接口(interface)。然后,您可以为有意义的类型(例如数组)实现该接口(interface)。

关于javascript - 如何映射任意 Iterables?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39425447/

相关文章:

javascript - 是否存在一个值 X 使得 new Date(X) 产生当前日期?

javascript - Module.exports 函数为变量返回 'undefined'

c++ - 如何在 C++ 中使用不同的参数多次调用一个函数

node.js - asn1 中出现意外标记 (len)

javascript - 在 es6 中等待而不需要响应

javascript - 链接中的 JavaScript 还是 onclick 中的 JavaScript 哪个先执行?

javascript - 传单中心弹出窗口和 map 标记

c# - C# 中的泛型和函数

r - 应用于嵌套函数

JavaScript - 数千次过滤数千个键