如何映射任意Iterables?

3 javascript iteration functional-programming iterable ecmascript-6

reduceIterables 编写了一个函数,现在我想得到一个map可以映射到任意Iterables 的泛型.然而,我曾经遇到过一个问题:由于Iterable小号抽象的数据源,map无法确定它(如类型Array,String,Map等).我需要这种类型来调用相应的标识元素/ concat函数.我想到了三种解决方案:

  1. 显式传递identity元素/ concat函数const map = f => id => concat => xs(这是详细的,但会泄漏内部API)
  2. 只有Iterable实现monoid接口的map (很酷,但引入了新类型?)
  3. 依靠的原型或构造的身份ArrayIterator,StringIterator等等.

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

Array.prototype.values.prototype.isPrototypeOf([].values()); // false
Array.prototype.isPrototypeOf([].values()); // false
Run Code Online (Sandbox Code Playgroud)

我的问题:

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

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

Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())) ====
Object.getPrototypeOf(Object.getPrototypeOf(("")[Symbol.iterator]()))
Run Code Online (Sandbox Code Playgroud)

原型的区别似乎是不可能的.

编辑:这是我的代码:

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
Run Code Online (Sandbox Code Playgroud)

行中的代码A产生所需的结果.然而,B产生一个Array而不是String和连接只能起作用,因为Strings和Numbers在这方面恰好相同.

编辑:似乎有什么原因让我感到困惑:我想使用iterable/iterator协议来抽象迭代细节,以便我的fold /展开和派生的map/filter等函数是通用的.问题是,如果没有身份/ concat协议,你就无法做到这一点.而我依靠原型身份的"小黑客"并没有成功.

@redneb在他的回答中提出了一个很好的观点,我同意他的观点,并非每个迭代都是"可映射的".但是,记住这一点我仍然认为以这种方式利用协议是有意义的 - 至少在Javascript中 - 直到将来版本中存在可用于此类用途的可映射或收集协议.

red*_*neb 5

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

因此,解决办法是定义一个新的接口(调用它Mappable, 仿函数,或任何你喜欢),但它必须是一个不同的接口.然后,您可以为有意义的类型实现该接口,例如数组.