Javascript 如何映射任意的可重用项?
我为Javascript 如何映射任意的可重用项?,javascript,functional-programming,ecmascript-6,iteration,iterable,Javascript,Functional Programming,Ecmascript 6,Iteration,Iterable,我为Iterables编写了一个reduce函数,现在我想导出一个可以映射到任意Iterables的通用map。但是,我遇到了一个问题:由于Iterables抽象了数据源,map无法确定它的类型(例如Array,String,map等)。我需要这个类型来调用相应的identity元素/concat函数。我想到了三个解决方案: 显式地传递identity元素/concat函数const map=f=>id=>concat=>xs(这很冗长,但会泄漏内部API) 只有mapIterables实现了m
Iterable
s编写了一个reduce
函数,现在我想导出一个可以映射到任意Iterable
s的通用map
。但是,我遇到了一个问题:由于Iterable
s抽象了数据源,map
无法确定它的类型(例如Array
,String
,map
等)。我需要这个类型来调用相应的identity元素/concat函数。我想到了三个解决方案:
const map=f=>id=>concat=>xs
(这很冗长,但会泄漏内部API)Iterable
s实现了monoid接口(很酷,但是引入了新类型?)ArrayIterator
,StringIterator
等的原型或构造函数标识Array.prototype.values.prototype.isPrototypeOf([].values()); // false
Array.prototype.isPrototypeOf([].values()); // false
我的问题是:
/ArrayIterator
/…)的原型在哪里李>StringIterator
- 有没有更好的方法来解决给定的问题
[][[Symbol.iterator]()
和(“”)[Symbol.iterator]()
似乎共享相同的原型:
Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())) ====
Object.getPrototypeOf(Object.getPrototypeOf(("")[Symbol.iterator]()))
通过原型进行区分似乎是不可能的
编辑:这是我的代码:
const values=o=>keys(o).values();
const next=iter=>iter.next();
常数foldl=f=>acc=>iter=>{
让循环=(acc,{value,done})=>done
?acc
:循环(f(acc)(值),下一个(iter));
返回回路(acc,next(iter));
}
//静态'map'版本仅适用于'Array',不是我想要的
常量映射=f=>foldl(acc=>x=>[…acc,f(x)])([]);
console.log(map(x=>x+x)([1,2,3].values());//A.
log(map(x=>x+x)(“abc”)[Symbol.iterator]());//B
我以前没有使用过,但在我看来,它本质上是一个接口,用于让您使用for
循环迭代容器对象。问题是,您试图将该接口用于它不是为之设计的东西。为此,您需要一个单独的接口。可以想象,一个对象可能是“可映射的”,但不是“可映射的”。例如,假设在一个应用程序中,我们使用二叉树,并通过遍历它们(比如按BFS顺序)来为它们实现iterable接口,因为该顺序对于这个特定的应用程序是有意义的。对于这个特殊的iterable,通用映射是如何工作的?它需要返回一个“相同形状”的树,但是这个特殊的可移植实现没有提供足够的信息来重建树
因此,解决这个问题的方法是定义一个新的接口(称之为
Mappable
,,或任何您喜欢的接口),但它必须是一个独特的接口。然后,您可以为有意义的类型(如数组)实现该接口。您可以比较对象字符串,尽管这不是傻瓜式的,因为在某些环境中存在已知的错误,并且在ES6中,用户可以修改这些字符串
console.log(Object.prototype.toString.call(“[Symbol.iterator]());
log(Object.prototype.toString.call([[Symbol.iterator]())代码>对于任意iterable,没有干净的方法可以做到这一点。可以为其创建地图并参考它
const iteratorProtoMap = [String, Array, Map, Set]
.map(ctor => [
Object.getPrototypeOf((new ctor)[Symbol.iterator]()),
ctor]
)
.reduce((map, entry) => map.set(...entry), new Map);
function getCtorFromIterator(iterator) {
return iteratorProtoMap.get(Object.getPrototypeOf(iterator));
}
通过定制iterables的可能性,还可以添加用于添加它们的API
为了提供用于连接/构造所需iterable的公共模式,可以为映射而不是构造函数提供回调
显式地传递identity元素/concat函数constmap=f=>id=>concat=>xs
是的,如果xs
参数没有公开构造新值的功能,那么这几乎总是必需的。在Scala中,每个集合类型都为此提供了一个特性,不幸的是,ECMAScript标准中没有与此匹配的内容
仅映射实现monoid接口的Iterables
好吧,是的,那可能是一种方法。您甚至不需要引入“新类型”,这方面的标准已经存在。然而,缺点是
- 大多数内置类型(
String
,Map
,Set
)不实现monoid接口,尽管它们是可移植的
- 不是所有的“可映射”都是幺半群李>
另一方面,并非所有的可映射性都是可映射的。试图在任意可重用项上编写映射
,而不返回到数组
结果注定要失败
因此,只需寻找Functor
或可遍历的接口,并在存在的地方使用它们。它们可能在内部构建在迭代器上,但这与您无关。您可能想做的唯一一件事是为创建此类基于迭代器的映射方法提供一个通用帮助器,以便您可以使用它装饰Map
或String
。该助手还可以将生成器对象作为参数
依赖于ArrayIterator、StringIterator等的原型或构造函数标识
这是行不通的,例如,类型化数组使用与普通数组相同的迭代器。由于迭代器没有访问迭代对象的方法,因此无法区分它们。但无论如何,您确实不应该这样做,只要处理迭代器本身,您最多应该映射到另一个迭代器,而不是映射到创建迭代器的iterable类型
ArrayIterator/StringIterator/的原型在哪里
它们没有全局变量,但是您可以在创建实例后使用Object.getPrototypeOf
访问它们。我知道这个问题已经发布了很多次了