Javascript 导出通用函数时遇到问题

Javascript 导出通用函数时遇到问题,javascript,flowtype,Javascript,Flowtype,我有一个助手函数库,我想导出它的咖喱版本 一小部分看起来像这样: export function curry2<A,B,C>(f: (x: A, y: B) => C): (x: A) => (y: B) => C { return (a) => (b) => f(a, b) } function _push<A>(item: A, items: Array<A>): Array<A> { return it

我有一个助手函数库,我想导出它的咖喱版本

一小部分看起来像这样:

export function curry2<A,B,C>(f: (x: A, y: B) => C): (x: A) => (y: B) => C {
  return (a) => (b) => f(a, b)
}

function _push<A>(item: A, items: Array<A>): Array<A> {
  return items.concat(item)
}

export const push = curry2(push)
因此,我试图通过注释导出的标识符来解决此问题:

export const push<A>: (item: A) => (items: Array<A>) => Array<A>
但在这一点上,我基本上要为我想要导出的每个函数重新编写一大块咖喱


有没有更好的方法来帮助Flow在const表达式中填充导出的泛型类型变量?

我怀疑如果没有更高类型,就无法定义
curry2
函数

type Function2<A, B, C> = (a: A, b: B) => C;
type CurriedFunction2<A, B, C> = (a: A) => (b: B) => C;

export function curry2<A, B, C>(f: Function2<A, B, C>): CurriedFunction2<A, B, C> {
  return (a: A) => (b: B): C => f(a, b)
}

export const push = curry2(function <A>(item: A, items: Array<A>): Array<A> {
  return items.concat(item)
})

我怀疑如果没有更高级的类型,就不可能定义
curry2
函数

type Function2<A, B, C> = (a: A, b: B) => C;
type CurriedFunction2<A, B, C> = (a: A) => (b: B) => C;

export function curry2<A, B, C>(f: Function2<A, B, C>): CurriedFunction2<A, B, C> {
  return (a: A) => (b: B): C => f(a, b)
}

export const push = curry2(function <A>(item: A, items: Array<A>): Array<A> {
  return items.concat(item)
})

请看我对同一问题的回答:

这里的主要限制是Flow根本不能推断多态类型。特别是,每当看到对多态函数的调用时,它都会立即用新的类型参数实例化类型参数,并且结果永远不会像Hindley Milner systems()那样“通用化”


这一限制的原因是,这种多态类型推断是不可判定的(参见Pierce,“有界量化是不可判定的”,POPL'92),并且子类型是JavaScript的一个必要特性(但对于类似ML的语言来说并非如此)。

请参见我对相同问题的回答:

这里的主要限制是Flow根本不能推断多态类型。特别是,每当看到对多态函数的调用时,它都会立即用新的类型参数实例化类型参数,并且结果永远不会像Hindley Milner systems()那样“通用化”


这一限制的原因是,这种多态类型推理是不可判定的(参见Pierce,“有界量化是不可判定的”,POPL'92),并且子类型是JavaScript的一个必要特性(但对于类似ML的语言来说并非如此)。

带有子类型的类型推理,多态,传统上,紧凑型一直是个问题。如果它能够适应流动,那么它可能是有用的

无论如何,流实际上似乎允许一些多态常量值

/@flow-strict
常数id:(T)=>T=(a:T):T=>a;
常量一般常量:(T)=>T=id(id);
重复常数:(U)=>[U,U]=(a:U)=>[a,a];
常数iddup:(T)=>[T,T]=id(dup);
常量dupdup:[(T)=>[T,T],(U)=>[U,U]]=dup(dup);
常数curry2=(f:(A,B)=>C)=>(A:A)=>(B:B):C=>f(A,B);
函数推送(项目:A,项目:数组):数组{
返回项目。concat(项目)
}
常量push2/*中断:(A)=>Array=>Array*/=curry2(\u push)
常量对:(A,B)=>[A,B]=(A:A,B:B):[A,B]=>[A,B]
常数对2/*断开:(A)=>(B)=>[A,B]*/=curry2(对)

我不确定它遵循的是什么规则,但它肯定不同于SML的值限制。

使用子类型、多态性和紧凑类型的类型推断传统上是有问题的。如果它能够适应流动,那么它可能是有用的

无论如何,流实际上似乎允许一些多态常量值

/@flow-strict
常数id:(T)=>T=(a:T):T=>a;
常量一般常量:(T)=>T=id(id);
重复常数:(U)=>[U,U]=(a:U)=>[a,a];
常数iddup:(T)=>[T,T]=id(dup);
常量dupdup:[(T)=>[T,T],(U)=>[U,U]]=dup(dup);
常数curry2=(f:(A,B)=>C)=>(A:A)=>(B:B):C=>f(A,B);
函数推送(项目:A,项目:数组):数组{
返回项目。concat(项目)
}
常量push2/*中断:(A)=>Array=>Array*/=curry2(\u push)
常量对:(A,B)=>[A,B]=(A:A,B:B):[A,B]=>[A,B]
常数对2/*断开:(A)=>(B)=>[A,B]*/=curry2(对)

我不确定它遵循的是什么规则,但它肯定不同于SML的值限制。

这似乎有同样的问题。导出的
push
表示它缺少类型参数A、B和C的注释。由于这是一个常量声明,因此无法提供它们。我的意思是目前不可能这样做,流不支持更高类型。这似乎有同样的问题。导出的
push
表示它缺少类型参数A、B和C的注释。由于它是一个常量声明,因此无法提供它们。我的意思是,目前这是不可能的,流不支持更高种类的类型
type Function2<A, B, C> = (a: A, b: B) => C;
type CurriedFunction2<A, B, C> = (a: A) => (b: B) => C;

export function curry2<A, B, C>(f: Function2<A, B, C>): CurriedFunction2<A, B, C> {
  return (a: A) => (b: B): C => f(a, b)
}

export const push = curry2(function <A>(item: A, items: Array<A>): Array<A> {
  return items.concat(item)
})
push: CurriedFunction2<A, Array<A>, Array<A>> // <= higher kinded type?
// @flow strict

const id: <T>(T) => T = <T>(a: T):T => a;
const genericConstant: <T>(T) => T = id(id);

const dup: <U>(U) => [U, U] = <U>(a: U) => [a, a];
const iddup: <T>(T) => [T, T] = id(dup);
const dupdup: [<T>(T) => [T, T], <U>(U) => [U, U]] = dup(dup);

const curry2 = <A,B,C>(f: (A, B) => C) => (a: A) => (b: B): C => f(a, b);

function _push<A>(item: A, items: Array<A>): Array<A> {
  return items.concat(item)
}

const push2 /*broken : <A>(A) => Array<A> => Array<A> */ = curry2(_push)

const pair: <A,B>(A, B) => [A, B] = <A, B>(a: A, b: B): [A, B] => [a, b]

const pair2 /*broken: <A,B>(A) => (B) => [A, B]*/ = curry2(pair)