无法导出curried通用函数

时间:2016-07-29 17:00:17

标签: javascript flowtype

我有一个帮助函数库,我想导出curried版本。

它的一小部分看起来像这样:

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)

但这并不奏效。 Flow抱怨表达式curry2(push),说:

- type parameter 'A' of function call. Missing annotation.
- type parameter 'B' of function call. Missing annotation.

所以我尝试通过注释导出的标识符来解决这个问题:

export const push<A>: (item: A) => (items: Array<A>) => Array<A>

但这不起作用,因为const表达式不能引入泛型类型变量。

所以我想我必须导出一个实际的函数才能注释它:

export function push<A> (item: A): (items: Array<A>) => Array<A> {
  return curry2(_push)(item);
}

但此时我基本上会为我要导出的每个功能重写一大块咖喱。

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

3 个答案:

答案 0 :(得分:2)

请在此处查看我对同一问题的回答:https://github.com/facebook/flow/issues/2165#issuecomment-236868389

这里的主要限制是Flow根本不会推断出多态类型。特别是,每当它看到对多态函数的调用时,它立即用新类型参数实例化类型参数,结果永远不会像Hindley-Milner系统(https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system)那样“泛化”。

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

答案 1 :(得分:0)

我怀疑在没有更高级别的类型

的情况下无法定义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)
})

最后一个定义意味着push具有类型

push: CurriedFunction2<A, Array<A>, Array<A>> // <= higher kinded type?

答案 2 :(得分:0)

具有子类型,多态性和紧凑类型的类型推断在传统上一直存在问题。 a recent paper describing a modification to Hindley-Milner inference可能会有用,如果它可以适应Flow。

无论如何,Flow实际上确实允许一些多态const值。 For example

// @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)

我不确定它遵循什么规则,但这绝对不同于SML的价值限制。

相关问题