如何指定未知/任意大小的泛型列表

问题描述 投票:1回答:2

注意:我开始关于这个主题的discussion on Github

我有一个zip函数,现在它被输入为相同类型T的iterables。我想为任意混合输入类型输入此类型,但仍然保留匹配的输出类型,例如,如果输入类型[Iterable<T>, Iterable<U>]我希望输出类型为Iterable<[T, U]>。任意输入大小都可以吗?我基本上想说,如果你有这个类型列表作为输入,你将把它们作为输出。

这是我的zip的当前版本:

export function *zip<T>(...iterables:Array<Iterable<T>>): Iterable<Array<T>> {
   const iterators = iterables.map(iterable => iter(iterable));
   while(true){
      const items = iterators.map(iterator => iterator.next());
      if (items.some(item => item.done)){
         return;
      }
      yield ((items.map(item => { return item.value }): Array<any>): Array<T>);
  }
}

export function *iter<T>(iterable:Iterable<T>): Iterator<T> {
   yield* iterable;
}

best solution目前的AndrewSouthpaw

declare function zip<A, B>(Iterable<A>, Iterable<B>): Iterable<[A, B]>;
declare function zip<A, B, C>(Iterable<A>, Iterable<B>, Iterable<C>): Iterable<[A, B, C]>;
declare function zip<A, B, C, D>(Iterable<A>, Iterable<B>, Iterable<C>, Iterable<D>): Iterable<[A, B, C, D]>;
export function *zip<T>(...iterables:Array<Iterable<T>>): Iterable<Array<T>> {
   const iterators = iterables.map(iterable => iter(iterable));
   while(true){
      const items = iterators.map(iterator => iterator.next());
      if (items.some(item => item.done)){
         return;
      }
      yield ((items.map(item => { return item.value }): Array<any>): Array<T>);
  }
}

当使用4个,3个或2个可迭代调用时,它按预期工作,当使用5个或更多个参数调用时,flow将简单地说只能使用4个或更少的参数调用zip。当然,我们可以添加尽可能多的函数签名,以使其适用于5,6或任意数量的N个参数,但这需要声明N个不同的签名(这有点难看)。另一方面,这种策略不允许有无限数量的参数(比如扩展运算符)。我还在寻找那个。


这提出了一个更普遍的问题,是否存在这种存在的语言?

我真的觉得这可以在理论上完成(不一定是在流程中),另一方面我不记得我已经完成/看过的静态类型语言(我也有兴趣看到任何语言的这种类型检查)。

更具体一点,我的感觉是,如果你有一个类型检查系统,其中(根据定义)所有类型都是静态知道的(任何变量都有一个已知的类型x),那么函数f: Array<Iterable<x>> -> Iterable<Array<x>>总是在已知类型x上调用。因此,我们应该能够静态地决定f将返回什么类型给定x(无论x是单个泛型类型还是泛型类型列表)。

对于函数本身也是如此,如果你有一个类型x作为输入,那么你只需要检查你的函数是否保留类型x

也许这需要在某些语言中递归地定义,这也很有趣。

flowtype typechecking static-typing
2个回答
2
投票

我们只能通过覆盖函数签名声明来实现这一点。这可能有所帮助:

declare function zip<A, B>(Iterable<A>, Iterable<B>): Iterable<[A, B]>
declare function zip<A, B, C>(Iterable<A>, Iterable<B>, Iterable<C>): Iterable<[A, B, C]>
declare function zip<A, B, C, D>(Iterable<A>, Iterable<B>, Iterable<C>, Iterable<D>): Iterable<[A, B, C, D]>
export function zip(a, b, c, d) {
  /* ... */
}

0
投票

这是工作解决方案。所有的功劳都归功于Flow团队的jbrown215,他在这里找到了using $ReadOnlyArray<mixed>的想法:

export function *zip<T: $ReadOnlyArray<mixed>>(...iterables:Array<Iterable<T>>): Iterable<Array<T>> {
   const iterators = iterables.map(iterable => iter(iterable));
   while(true){
      const items = iterators.map(iterator => iterator.next());
      if (items.some(item => item.done)){
         return;
      }
      yield ((items.map(item => { return item.value }): Array<any>): Array<T>);
  }
}

export function *iter<T>(iterable:Iterable<T>): Iterator<T> {
   yield* iterable;
}
© www.soinside.com 2019 - 2024. All rights reserved.