我为 Iterable
编写了一个 reduce
函数,现在我想派生一个可以映射到任意 Iterable 的通用
但是,我遇到了一个问题:由于 map
Iterable
抽象了数据源,map
无法确定它的类型(例如 Array
, String
、Map
等)。我需要这种类型来调用相应的标识元素/concat 函数。我想到了三种解决方案:
- 显式传递标识元素/concat 函数
const map = f => id => concat => xs
(这很冗长并且会泄漏内部 API) - 只映射实现了 monoid 接口(interface)的
Iterable
(这很酷,但引入了新类型?) - 依赖
ArrayIterator
、StringIterator
等的原型(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
并且连接只起作用,因为 String
和 Number
在这方面恰好是等价的。
编辑: 我这样做的原因似乎很困惑:我想使用可迭代/迭代器协议(protocol)来抽象迭代细节,以便我的折叠/展开和派生映射/过滤器等功能是通用的。问题是,如果没有身份/连接协议(protocol),您将无法执行此操作。我依靠原型(prototype)身份的小“技巧”没有奏效。
@redneb 在他的回应中提出了一个很好的观点,我同意他的观点,即并非每个可迭代对象也是“可映射的”。但是,牢记这一点,我仍然认为以这种方式使用该协议(protocol)是有意义的 - 至少在 Javascript 中是这样,直到可能在未来的版本中有用于此类用法的可映射或收集协议(protocol)。
最佳答案
我没有用过iterable protocol以前,但在我看来,它本质上是一个接口(interface),旨在让您使用 for
循环迭代容器对象。问题是您正试图将该界面用于其设计目的以外的用途。为此,您需要一个单独的界面。可以想象,一个对象可能是“可迭代的”但不是“可映射的”。例如,假设在一个应用程序中我们正在使用二叉树,并且我们通过以 BFS 顺序遍历它们来为它们实现可迭代接口(interface),只是因为该顺序对这个特定应用程序有意义。通用 map 如何适用于这个特定的可迭代对象?它需要返回一个“相同形状”的树,但这个特定的可迭代实现没有提供足够的信息来重建树。
因此解决方案是定义一个新接口(interface)(将其命名为 Mappable
、Functor 或任何您喜欢的名称),但它必须是一个独特的接口(interface)。然后,您可以为有意义的类型(例如数组)实现该接口(interface)。
关于javascript - 如何映射任意 Iterables?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39425447/